|
Boost : |
Subject: Re: [boost] [castor] Interest in Logic Paradigm for C++ ?
From: Roshan (roshan_naik_at_[hidden])
Date: 2010-05-08 02:34:15
On Thu, 06 May 2010 21:12:52 -0600, OvermindDL1 <overminddl1_at_[hidden]>
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
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk