
On Thu, 06 May 2010 21:12:52 -0600, OvermindDL1 <overminddl1@gmail.com> wrote:
Other things to discuss too, but I have to go, perhaps later. What do you think of that style interface though, and you could easily build upon and combine them and many other things.
There are certainly many other approaches and there might be potential in what you suggest. It is a bit exhausting to critique each design alternative in detail as each design requires a lot of prototyping and refining. A good way to get a feel for the issues in any alternative design is to rewrite the && and || relations and some relations from tutorial such as ancestor() using the alternative design. Anyway I'll try anyway to comment on this approach as it is very natural to expect a design based on iterators. Building this model of computation on top of boost::range/iterators instead of coroutines requires creation of custom iterator types for relations that require imperative definitions. Defining relations imperatively is not uncommon. Iterator types are a severe pain to implement. Coroutine's are vastly easier to define. This is probably the biggest issue. Subroutines and coroutines are more fundamental computational ideas than iterators. Iterator objects are themselves coroutines (just with different syntax). Coroutine model is also more natural than iterators when complex evaluation is expected. IMHO, if coroutines were natively available, iterators in their current form (although very useful), would have a different footprint on the C++ mindset. Many like to suggest the iterator based approach as you can use the Boost::Foreach or range based for loops. Thats easier to digest for C++ programmers who are not accustomed to coroutines. But those constructs were created specifically to help with the repetitive use of the verbose for() pattern on iterators. This could be achieved by an adapter : for( auto res : iterable(father("Frank",c) ) ) { cout << *c << "\n"; } or more appropriately.. by extending these looping constructs to be coroutine aware as is the case in other languages. while( father("Frank",c) ) { cout << *c << "\n"; } Also I like to explicitly see the arity, parameter names and types for a relation ... which is how we write functions in C++. relations are LP's alternative to functions. For a reader it is not nice to have to infer the arity by examining the max argN in the entire expression. It also has to scale to any arity. So the current syntactic approach is more natural IMHO. Esp for teaching. As a matter of readability, I prefer named variables over r.get<0>() and r.get<1>() expressions. Easier to read & write and dont require you to remember what each one means. This approach r.get<0>() is also more typo-friendly for repetitive usage. arg1 needs to be a type that can be inspected if it is currently initialized. Also arg1=="Sam" must be a relation/coroutine (not an ordinary function object). Design decision to use eq and stay away from using == operator is discussed in the design doc. One benefit is, it allows for more named variations to unification eq_f, eq_seq etc. This approach has heavy reliance on library based type deduction for return and parameter types of sub expressions. Given the current state of C++ (not C++0x) this deduction is not very robust, has its limitations and difficult to troubleshoot. Since relations are a basic alternative to functions and not domain specific like DSELs, I feel, relations should preferably be less reliant on compile-time intensive techniques. -Roshan