|
Boost : |
From: Eric Niebler (eric_at_[hidden])
Date: 2008-03-17 22:15:57
Markus Werle wrote:
>
> ---- Task 1 --------------
> Consider I need to flatten a tree into a sum:
>
> template<int I> struct arg {};
>
> proto::terminal<arg<1> >::type a;
> proto::terminal<arg<2> >::type b;
> proto::terminal<arg<3> >::type c;
> proto::terminal<arg<4> >::type d;
>
> a + b + c + d
>
> has type expr<tag::plus, arg2<a tree structure> >
>
> but I need a template function make_flat
> taking arbitray expressions and return
> expressions of type
>
> expr<sum, args4<all args in the typelist> >
>
> How can I do this in proto?
This one is easy:
proto::unpack_expr<sum>(
fusion::as_vector(
proto::flatten(a + b + c + d)
)
);
fusion::as_vector() is needed because proto::unpack_expr() currently
requires a random access sequence, and proto::flatten() returns a
forward sequence. I should loosen that requirement.
> -----------
> Task 2: Next step:
>
> a - b + c should first be transformed into
> a + (-b) + c and then transformed into the sum.
>
> Could you please provide full compilable examples?
See attached. The transform you're looking for is:
struct Transform
: or_<
terminal<_>
, when<
minus<Transform, Transform>
, _make_plus(
Transform(_left)
, _make_negate(Transform(_right))
)
>
, nary_expr<_, vararg<Transform> >
>
{};
> Task 3: Next step:
>
> I want to detect simultaneous occurences of
> x and -x and have them dropped from the typelist of my sum.
> Please provide an example that detects this for terminals only,
> then one which also works for (a*b - a*b) and returns
> expr<tag::nil, nulllist> (BTW, is there a nil/null tag in proto?)
>
>
> ---------
>
> Task 4: Write an expand function that for
> a*(b+c) returns a type representation a*b+a*c
>
I'm afraid I don't have the time for these right now, but I would
approach them by using the Transform and then flatten() to produce a
flat Fusion sequence. Then I would manipulate the Fusion sequence using
Fusion algorithms. After I have reduced the sequence, I would use
unpack_expr() to build the resulting "sum" expression.
To detect whether some complicated Proto expression E1 is the same as
another E2, you can use proto::matches<E1, E2>, because every expression
type is a grammar that matches itself.
Good luck!
-- Eric Niebler Boost Consulting www.boost-consulting.com
#include <iostream>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/xpressive/proto/proto.hpp>
#include <boost/xpressive/proto/debug.hpp>
#include <boost/xpressive/proto/context.hpp>
#include <boost/xpressive/proto/transform.hpp>
using namespace boost;
template<int I> struct arg
{
friend std::ostream &operator <<(std::ostream &sout, arg)
{
return sout << "arg<" << I << ">";
}
};
proto::terminal<arg<1> >::type a;
proto::terminal<arg<2> >::type b;
proto::terminal<arg<3> >::type c;
proto::terminal<arg<4> >::type d;
struct sum
{
friend std::ostream &operator <<(std::ostream &sout, sum)
{
return sout << "sum";
}
};
using namespace proto;
struct Transform
: or_<
terminal<_>
, when<
minus<Transform, Transform>
, _make_plus(Transform(_left), _make_negate(Transform(_right)))
>
, nary_expr<_, vararg<Transform> >
>
{};
int main()
{
int ignore = 0;
// 1)
display_expr(
unpack_expr<sum>(
fusion::as_vector(
flatten(a + b + c + d)
)
)
);
// 2)
display_expr(
a - b + c
);
display_expr(
Transform()(a - b + c, ignore, ignore)
);
display_expr(
Transform()(a - b + c, ignore, ignore)
);
display_expr(
unpack_expr<sum>(
fusion::as_vector(
flatten(Transform()(a - b + c, ignore, ignore))
)
)
);
return 0;
}
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk