Boost logo

Boost :

Subject: Re: [boost] [proto] reorganized users' guide
From: Eric Niebler (eric_at_[hidden])
Date: 2008-10-17 16:47:35


troy d. straszheim wrote:
> Eric Niebler wrote:
>>
>> I've just completed a major reorg of Proto's docs, with significant
>> portions clarified or completely rewritten. I intend to merge these
>> changes to the release branch soon. I encourage any and all interested
>> parties to click around and offer feedback.
>
> Very, very nice. And an amazing library. You could probably write an
> entire book about programming inside the C++ type system that would be a

It would be a ... ? Is this a MadLib? ;-)

> I'll be going those docs
> carefully. I've been spending quite a lot of time with proto recently.
> I've been doing lots of small experiments and could probably generate a lot
> of little examples if you're interested.
>
> I'm wondering... say I have a transform like:
>
> struct Transform :
> proto::or_<
> proto::when<proto::terminal<std::vector<float> >, proto::_value>
> , proto::when<proto::terminal<float>, proto::_value>
> , proto::when<proto::binary_expr<proto::tag::multiplies, Transform,
> Transform>,
> Multiply(Transform(proto::_child0), Transform(proto::_child1))>
> >
> {};

What's Multiply?

> And the idea is that the proto::callable Multiply, and its return_type,
> vary depend on the evaluated types of proto::_child0, and proto::_child1.
> When fully evaluated each will be either vector<float> or float,
> and, say, one wants float * float to return a float, float * vector to
> return a vector,
> and vector*vector to return some kind of matrix. I noticed the docs
> for lazy<>:
>
> > lazy<> is useful as a higher-order transform, when the transform to
> be applied
> > depends on the current state of the transformation. The invocation of
> the make<>
> > transform evaluates any nested transforms, and the resulting type is
> treated as
> > a CallableTransform, which is evaluated with call<>.
>
> I could use a hint or two here...

I don't think you need proto::lazy<>. You seem to be implementing a
linear algebra library, is that right? I would start by implementing
function objects for multiplying a vector by a float and a vector by a
vector. Then I would invoke them from your grammar as ...

struct Scalar
   : or_<
         when<terminal<float>, _value>
       , when<multiplies<Scalar, Scalar>, _default<Scalar> >
>
{};

struct Vector
   : or_<
         when<terminal<std::vector<float> >, _value>
       , when<
             multiplies<Vector, Scalar>
           , MyVecMult(Vector(_left), Scalar(_right))
>
>
{};

struct Matrix
   : or_<
         when<terminal<MyMatrix<float> >, _value>
       , when<
             multiplies<Vector, Vector>
           , MyMtrixMult(Vector(_left), Vector(_right))
>
>
{};

struct LinearAlgebra
  : or_< Scalar, Vector, Matrix >
{};

All that remains to be done is implement the MyVecMult and MyMtrixMult
function objects. And although you can use this to actually evaluate the
expressions, you'll probably instead want to use something like this to
simply compute the result type (scalar, vector or matrix), create an
object of that type, and then use a different transform to fill it in
all in one pass to avoid the creation of temporaries. I leave that as an
exercise for you. :-)

-- 
Eric Niebler
BoostPro Computing
http://www.boostpro.com

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