On Wed, Sep 1, 2010 at 1:40 PM, Jonathan S. Shapiro <[email protected]>wrote:

> I have been thinking more about mixfix and its relationship to macro
> processing. Actually, this was prompted in part by a weird thought
> concerning blocks.
>
> We can view
>
>   let x = 5 in { body }
>
> as a construct in which "{ body }" is a *procedure* taking no arguments,
> where the semantics of LET is to apply (call) the procedure. The only reason
> to consider this is that it makes code blocks into convenient first-class
> objects.
>
> Given which, we could introduce something like:
>
>    mixfix while_do_ : lambda(test, block) {
> implementation-of-while-loop-calling-block }
>
> That is: we exploit the fact that lambdas provide a form of call-by-name.
>
> But this got me to thinking about:
>
>   mixfix _and_ : lambda(lhs,rhs) { if rhs then if lhs then true else false
> else false }
>
> the problem here is that evaluation under _and_ is lazy, and that requires
> either call-by-name or call-by-need (which is memoized call-by-name).
>
> Now the reason I am raising this is that many examples of macros can be
> turned into procedures in a language that implements call-by-need.
>
> All of this is a thought for much later in the game, but I wanted to throw
> it out and see if anybody thought it was interesting. It's not at all hard
> to do.
>


You've mentioned doing effects for BitC in the future. One consequence of
adopting non-strict evaluation is that a single-argument function type gets
two effects instead of just one, since the input is a thunk, not a
fully-reduced value. This isn't problematic in a strict technical sense, but
it does add a non-trivial number of  complexity-straws. Ben Lippmeier's
dissertation (highly recommended!) has an excellent presentation of the
design and implementation of call-by-need in a default-call-by-value
language with effects:

http://www.cse.unsw.edu.au/~benl/papers/thesis/

He also discusses why Disciple is call-by-value, even though it inherits
much else from Haskell.


I've thought about combining lazy and strict evaluation a bit before, and I
haven't been able to come up with a satisfying design to integrate the two.
On the one hand, it seems like it's good to have transparent syntax for lazy
code, because otherwise, why not just use explicit zero-arity functions? On
the other hand, for a language that's supposed to have a transparent mapping
to the machine level, it's not immediately clear that giving
indistinguishable syntax to such semantically different operations is a good
idea.

You've mentioned before that one bad syntax is better than two good ones.
This might be an analogous situation for semantics. So far, my only
conclusion has been that it seems safer, from a design and complexity-budget
perspective, to give syntactic constructs with call-by-value semantics which
take good advantage of light syntax for anonymous functions.

For example, the Python way of iterating through a range is a
language-provided statement, in the C tradition:

for var in range(0, n):
  foo(var)

but the Ruby (or Scala, or _____) analogue is a simple expression, with no
keywords needed. In Rubyish syntax:

range(0, n).each  { |var| foo(var) }

They're not exactly equivalent, though, since the Python example desugars to
doing external iteration via a common protocol, whereas the Ruby version
does internal iteration, and doesn't involve any syntactic sugar.
_______________________________________________
bitc-dev mailing list
[email protected]
http://www.coyotos.org/mailman/listinfo/bitc-dev

Reply via email to