Boost logo

Boost :

From: Brian McNamara (lorgon_at_[hidden])
Date: 2004-02-18 13:11:25


On Wed, Feb 18, 2004 at 07:07:43AM +0000, Matthew Vogt wrote:
> Brian McNamara <lorgon <at> cc.gatech.edu> writes:
> > Well, technically you don't even need lambda to implement monads. But
> > to do monads well/easily, you need syntax sugar (along the lines of
> > Haskell's "do" notation or FC++'s comprehensions). This sugar requires
> > explicit lambda variables (the same kind you see in FC++ lambda's
> > let/letrec). It's unclear to me if/how to do that with (or extend)
> > boost::lambda in a natural way to get this.
>
> So, the less-concise syntax of fcpp::lambda means that there's more often
> a term in an expression which can be used to cause an operator overload to
> be selected from the lambda library?

Sorry, I don't quite understand the question.

Here's an example which may or may not help:

In Haskell you can write a list comprehension like this:

   [ x+y | x <- [1,2,3], y <- [2,3], x<y ]

which means "a list of all the values x+y where x is selected from the
list [1,2,3] and y from the list [2,3], under the condition x<y".

In FC++ you can write it as

   // where l_123 and l_23 are lists with those values
   compM<ListM>()[ X %plus% Y |
      X <= l_123, Y <= l_23, guard[ X %less% y ] ]

This desugars (just as in Haskell) into code with calls to the basic
monad functions (bind, unit, zero):

   l_123 ^bindM<ListM>()^ lambda(X)[
      l_23 %bindM<ListM>()% lambda(Y)[
         if1[ X %less% Y,
              unitM<ListM>()[ X %plus% Y ],
              zeroM<ListM>() ] ] ]

You can see the nested lambdas here; in boost::lambda-speak, X would be
_1, and Y would be protect(_1), I think. Most monadic computations
desugar into nested lambdas. When you have a "named variable" scheme as
your representation for lambda expressions, it is pretty straightforward
to express code involving nested lambdas. When you have a "positional
placeholder" scheme, as in boost::lambda, it is not as easy to express
nested lambdas. (The trade-off, of course, is that the Boost scheme is
more succinct in cases which don't have heavily nested lambdas--and this
is the common case for most (non-monadic) C++ code.)

There's also the "sugar" issue, that we overload operators like "<=" to
mean "gets" (that is, bind this lambda variable to this monad
computation), which is relatively incompatible with boost::lambda's
scheme of overloading operators to mean what that are in C++. Both
operator overloading schemes are valuable; in boost, stuff like this
   40 <= _1 // a concise way to express this function
is great; in FC++ (especially if you are already accustommed to reading
Haskell), the "compM" version with the "<="s is much more readable than
the version with all the bindMs.

In the end, there are two very different design goals, and depending
upon which one you want to "optimize" (make easiest to express), you
naturally gravitate towards one kind of design or the other.

-- 
-Brian McNamara (lorgon_at_[hidden])

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk