Boost logo

Boost :

From: Douglas Paul Gregor (gregod_at_[hidden])
Date: 2003-10-22 12:49:45


On Wed, 22 Oct 2003, Brian McNamara wrote:
> There are a number of other minor problems which have accumulated.
> Here's a new version which is hopefully bug-free:
>
> ----------------------------------------------------------------------
> typedef int Literal;
> template<typename V> struct Add_ : public tuple<V, V> {};
> template<typename V> struct Sub_ : public tuple<V, V> {};
> template<typename V> struct Mul_ : public tuple<V, V> {};
> template<typename V> struct Div_ : public tuple<V, V> {};
> typedef recursive_variant<
> Literal,
> Add_<recursive_variant_>,
> Sub_<recursive_variant_>,
> Mul_<recursive_variant_>,
> Div_<recursive_variant_>
> >::type Expr;
> typedef Add_<Expr> Add;
> typedef Sub_<Expr> Sub;
> typedef Mul_<Expr> Mul;
> typedef Div_<Expr> Div;
>
> int eval( Expr e ) {
> return switch_<int>( e )
> |= case<Add>( eval(_1)+eval(_2) )
> |= case<Sub>( eval(_1)-eval(_2) )
> |= case<Mul>( eval(_1)*eval(_2) )
> |= case<Div>(
> if_then_else_return(eval(_2)==0,
> throw_exception("div by 0"),
> eval(_1)/eval(_2) )
> |= case<Literal>( _1 )
> ;
> }
> ----------------------------------------------------------------------
>
> That almost works "out of the box"; the only thing else is that stuff
> like
>
> |= case<Add>( eval(_1)+eval(_2) )
>
> isn't right, because the proposed switch_ construct would want it to be
>
> // pseudocode for clairty
> |= case<Add>( lambda(a){ eval( get<1>(a) )+eval( get<2>(a) ) } )
>
> Right?

Right, but I was cheating a bit, by assuming that:

  |= case<Add_>( eval(_1) + eval(_2) )

is equivalent to

  |= case<Add>( lambda(a){ eval( get<1>(a) )+eval( get<2>(a) ) } )

That is, since we can distinguish Add_ (a template) from Add (a type), we
can automagically uncurry (at one time I naively called this "unpacking")
the value. Evil? Sure. Useful? Damn right it is.

> Oh, duh. This is what Haskell calls "uncurry". Wow! Ok, so the long
> and the short of it is that I should be writing
>
> |= case<Add>( uncurry( eval(_1)+eval(_2) ) )

Ah ha! That's the right term. Even if the rest of this discussion goes
nowhere, we should probably write uncurry... perhaps it should just be
syntactic sugar for a tuple visitor (like variant has visitors)?

> > I'm not sure if I care all that much about matching on values. I do, however,
> > think that using tags can shorten code a bit.
>
> I just realized I didn't communicate what I meant here. By "matching
> on values", I meant being able to use, e.g., "_1" inside the "Add" case
> to mean the left-hand expression tree. I did _not_ intend to imply
> that I wanted to be able to have "case 0", "case 1", and "case n" arms,
> for example.

Ah, okay. I understand now.

        Doug


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