On 8/9/2010 5:39 PM, Manjunath Kudlur wrote:
>> Actually, I think your users will be forced to do: (module->*func)(...)
>> because of the precedence. That's pretty ugly. But I see where you're
>> going. Your scheme could be made to work as you describe, I think.
> 
> Yes, you are right, I had forgotten about the precedence.
> 
>> I'm left wondering why you want this, though. In what way is it better
>> than just defining some mutually recursive functions?
> 
> How would you do that? Do you have some other mechanism in mind? 

I was just talking about plain ol' vanilla C-style functions. Kickin' it
old school.

> To be
> clear, I want the ability to "name" some proto expressions, and freely
> "call" these expressions in other expressions in a mutually recursive
> manner, just like in the example I have shown. My use case is to
> provide the user with a set of data-parallel primitives that he can
> freely compose to form bigger functions.

Now I have a very fuzzy picture, but it's still not clear yet. Anyway,
it seems like an interesting programming challenge so I took a crack at
it myself. I got distracted so didn't finish it, but here's what I came
up with so far.

The biggest problem I saw was that the syntax "module.func(a,b,c)" can
mean two different things. When building the symbol table, it should
create an expression template. But outside of symbol-table-building, it
should actually evaluate the function, using the symbol table to
statically look up the functions to evaluate. This is tricky! But I
think it can be accomplished by using two different domains. I am too
tired to explain what I mean, so I'll just post what I have so far and
hope that you'll get the idea.

-- 
Eric Niebler
BoostPro Computing
http://www.boostpro.com
#include <boost/proto/proto.hpp>
#include <boost/proto/proto_typeof.hpp>
#include <boost/fusion/container/vector.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <vector>
#include <iostream>

using namespace std;

namespace mpl=boost::mpl;
namespace proto=boost::proto;
using proto::_;

template<typename>
struct arg {};

proto::terminal<arg<mpl::int_<0> > >::type const _1 = {{}};
proto::terminal<arg<mpl::int_<1> > >::type const _2 = {{}};
proto::terminal<arg<mpl::int_<2> > >::type const _3 = {{}};

template<typename>
struct func {};

struct _map {};
proto::terminal<_map>::type const map = {{}};

struct _symbol_table_tag {};

//// Eval would be used to actually evaluate a function
//// invocation of module.func(x,y,z), as opposed to
//// simply creating the symbol table. This is incomplete.
//struct Eval
//  : proto::or_<
//        proto::when<
//            proto::terminal< arg<_> >
//          , // TODO look up argument in state tuple
//        >
//      , proto::when<
//            proto::function<
//                proto::member<
//                    proto::terminal<_symbol_table_tag> // the module
//                  , proto::terminal< func<_> >   // the function
//                >
//              , proto::vararg<Eval>
//            >
//          , // TODO downcast the module to access the symbol
//            // table. Look up the function in the symbol table.
//            // Then evaluate the function.
//        >
//      , proto::otherwise<
//            proto::_default<Eval>
//        >
//    >
//{};

#define MK_FUNC_MEMBER(R, DATA, I, ELEM) ((func<mpl::int_<I> >, ELEM))

// Define the symbols. Probably should be parameterized on a
// domain instead of (or in addition to) the symbol table.
#define DECLARE_SYMBOL_TABLE(NAME, SYMBOLS)                                     
                    \
    template<typename Module>                                                   
                    \
    struct NAME                                                                 
                    \
    {                                                                           
                    \
        typedef Module module_type;                                             
                    \
        module_type derived() { return *static_cast<module_type *>(this); }     
                    \
        module_type const derived() const { return *static_cast<module_type 
const *>(this); }       \
        BOOST_PROTO_BASIC_EXTENDS(                                              
                    \
            proto::terminal<_symbol_table_tag>::type                            
                    \
          , NAME<Module>                                                        
                    \
          , proto::default_domain                                               
                    \
        )                                                                       
                    \
        BOOST_PROTO_EXTENDS_MEMBERS(BOOST_PP_SEQ_FOR_EACH_I(MK_FUNC_MEMBER, ~, 
SYMBOLS))            \
        static NAME<Module> const self;                                         
                    \
    };                                                                          
                    \
    template<typename Module>                                                   
                    \
    NAME<Module> const NAME<Module>::self = {}

// Given a set of symbols and some declarations involving the
// symbols, build a symbol table.
#define DECLARE_MODULE(NAME, SYMBOLS, DECLS)                                    
                    \
    struct NAME : SYMBOLS<NAME>                                                 
                    \
    {                                                                           
                    \
        typedef BOOST_TYPEOF(proto::deep_copy(DECLS)) table_type;               
                    \
        table_type const table;                                                 
                    \
        NAME()                                                                  
                    \
          : table(proto::deep_copy(DECLS))                                      
                    \
        {}                                                                      
                    \
    }

// This declares a bunch of symbols that we can later use
// in a module to define function declarations
DECLARE_SYMBOL_TABLE(
    symbol_table
  , (vadd)
    (negmul)
    (det_inverse)
    (vmul)
    (fib)
    (precondition)
);

// This declares a module containing function declarations.
DECLARE_MODULE(
    module
  , symbol_table
  , (
        self.vadd                = _1 + _2
      , self.negmul              = -self.vmul(_1, _2)
      , self.det_inverse         = 1 / (_1 * _3 - _2 * _2)
      , self.vmul                = _1 * _2
      , self.fib                 = self.fib(_1 - 1) + self.fib(_1 - 2)
      , self.precondition        = self.vmul(map(self.det_inverse, _1, _2, _3), 
_1)
    )
);

int main()
{
    module mod;
    std::vector<int> a, b, c;
    
    // Right now, this just creates an expression template
    // representing the expression. We'd need to hook this
    // to get it to actually evaluate the expression.
    mod.precondition(a, b, c);

    // This displays a very small tree because the decls
    // have been type-erased. All that type information is
    // available statically, so that's not a problem.
    proto::display_expr(mod.precondition(a, b, c));
}
_______________________________________________
proto mailing list
proto@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/proto

Reply via email to