
On Mon, Feb 12, 2018 at 11:28 AM, Brook Milligan <brook@nmsu.edu> wrote:
On Feb 8, 2018, at 2:15 PM, Zach Laine via Boost <boost@lists.boost.org> wrote:
So, I have been very resistant to adding another new evaluation mode. Instead, I think something like this should be usable in most cases:
// Let's assume the existence of a my_make_term() function that takes a Yap terminal // and a Context &, and returns a new Yap terminal. template <typename Context> struct transform_terminals_with_context { // Base case. Note that I'm ignoring placeholders entirely for this // example (they're easy to special-case if necessary). template <typename T> auto operator() (yap::terminal_tag, T && t) { return my_make_term(std::forward<T>(t), context_); }
// Recursive case: Match any binary expression. template <typename Tag, typename LExpr, typename RExpr> auto operator() (Tag, LExpr const & left, RExpr const & right) { return yap::make_expression<yap::detail::kind_for<Tag>>( boost::yap::transform(left, *this), boost::yap::transform(right, *this)); }
// Recursive case: Match any unary expression. template <typename Tag, typename Expr> auto operator() (Tag, Expr const & expr) { return yap::make_expression<yap::detail::kind_for<Tag>>( boost::yap::transform(expr, *this)); }
// Ternary and call are added as necessary.
Context & context_; };
So just to be sure, I made up what I think is a complete example to illustrate your main Yap idiom. The features I wanted to capture are:
- the evaluate(transform(expr,xform)) idiom
- move-only terminals
I'm not sure what you mean by this, because the terminal type in your example is copyable. Do you mean showing how to force copies with moves, or something else? - terminals with no particular expression semantics that are transformed
into values that have expression semantics
- a customization point in the transform to support arbitrary user-defined types being added to the transform
- ignore context-dependent transforms for now; given this pattern those are easy to support since a transform object is available everywhere a terminal is transformed into a value
In what follows, I am thinking of the "user" namespace as user-defined code and the "N" namespace as library code.
Have I missed anything of note?
Yes, that covers the main moving parts as far as I can see.
Please also note that yap::detail::kind_for<Tag> in your code above should not be in the "detail" namespace as that is something that library writers building things upon Yap will be using and therefore it is not an implementation detail. I also think you didn't quite get the yap::make_expression<>() call correct in the above code.
Agreed. Once added, kind_for<>() would go in yap::. Zach