|
Boost : |
Subject: Re: [boost] [castor] Interest in Logic Paradigm for C++ ?
From: vicente.botet (vicente.botet_at_[hidden])
Date: 2010-05-07 10:10:49
Hi,
----- Original Message -----
From: "Roshan" <roshan_naik_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Friday, May 07, 2010 11:38 AM
Subject: Re: [boost] [castor] Interest in Logic Paradigm for C++ ?
>
> On Wed, 05 May 2010 12:57:07 -0600, vicente.botet
> <vicente.botet_at_[hidden]> wrote:
>
>> * Separation between relation structure and bindings
> [..snip..]
>> will build twice the relation generated by the function child. This
>> should be an expensive operation if instead of 5 record child had 1000,
>> or even more.
>
>
> This example is only introductory and too simplistic to address your valid
> concern. Its purpose is to demonstrate some basic concepts driving this
> paradigm and is used
> classically in teaching Prolog.
>
> In practice, you will not hard code so many records ... you retrieve it
> from some database/container. Then the relation would
> merely return something that references the record-set with ability to
> perform enumeration/look-up.
The problem was that the dynamic relation example builds this tree relation. I think that the efficient alternative must be included soon on the tutorial, as otherwise people statrts to look for better implementations. Is the efficient alternative based on co-routines?
>> * Relation structure definition
>>
>> relation_schema<string,string> father = gender(_1,"male")&& child(_2,_1);
>>
>> child could be defined as follows:
>>
>> relation_schema <string, string> child;
>>
>> child |= eq(_1,"Sam") && eq(_2,"Mary");
>> child |= eq(_1,"Denise") && eq(_2,"Mary") ;
>> child |= eq(_1,"Sam") && eq(_2,"Frank");
>> child |= eq(_1,"Denise") && eq(_2,"Frank");
>> child |= eq(_1,"Frank") && eq(_2,"Gary");
>>
>
> This style leads to "open ended" relations. Anybody can inject clauses
> into child or father...dangerous. then you need protection mechanisms.
> The current style ensures "closed" relations by default... which is
> similar to C++ functions being "closed".
A dynamic relation is not closed neither or is it?
> This design is a deliberate breakaway from Prolog.
>
> _1 , _2 have limitations on arity. relations are direct computational
> equivalents in LP to functions
> Therefore the current syntax modeled to be closer to around
> functions/expressions rather than data.
> It allows things like member relations, virtual member relations and
> template relations etc. Which in
> turn allows us to extend existing OO design patterns to the LP.
Definitely I need to read completly the documentation. Do you have some tutorials on which we see how this integration is achieved?
>
> Also I feel the syntax
>
> relation child = x || y || z ;
>
> is nicer to read/type than
>
> relation_schema<..> child;
> child |= x;
> child |= y;
> child |= z;
I agree for this example. I will comeback when will have a concret used case of dynamic configuration of relations.
>> * Bindings
>
> Think of it in terms currying in the functional paradigm.
> When you take a (binary) function and bind one of its argument you still
> have a (unary) function.
> Same with relations. Don't think of a relation as data... even if the
> initial examples in the tutorial
> gives you that feeling. think of them as rules perhaps (rather than facts)
> ..if it helps.
I know that.
>> * Typed relations
>> I'm not sure of ot is possible to implement the following, but let me
>> continue.
>>
>> The preceding example uses a type erasure to have untyped relation.
>> Castor could also have typed relations. typed_relation<T1,...,Tn>
>> can be considered as a container of tuple<lref<T1>,...,lref<Tn>>
>>
>> typed_relation<string,string> father_child = father(_1, _2);
>> for(tuple<lref<string>,lref<string> > r&: father_child) {
>> lref<string> f, c;
>> tie(f,c) = r;
>> cout << c << " is " << f << "'s child\n";
>> }
>>
>> or using iterators
>>
>> for(typed_relation<string,string>::iterator it= father_child.begin();
>> it!=father_child.end();++it) {
>> lref<string> f, c;
>> tie(f,c) = *it;
>> cout << c << " is " << f << "'s child\n";
>> }
>>
>> There are surely a lot of errors on the preceding design, but I think is
>> worth see if it is possible to adapt it to your library.
>
>
> Perhaps, but I don't think I see the motivating benefits. The syntax is
> getting poorer.
> Will need more fleshed out details with definitions of child(), father() &
> ancestor().
>
> If you really like to use "range based for loops" or "iterator style
> enumeration" its nicer to :
>
> for( auto res : iterable(father(x,y)) )
> cout << *x << " " << *y <<"\n";
>
> where iterable adapts an arbitrary relation/coroutine into an iterator.
I like this. Is iterable part of the library or an alternative design?
>> * dynamic relations / views
>> Example extracted from the tutorial
>>
>> list<pair<string,string> > genderList = ...;
>> // dynamically building a relation
>> Disjunctions gender_dyn(lref<string> p, lref<string> g) {
>> Disjunctions result;
>> list<pair<string,string> >::iterator i;
>> for( i=genderList.begin(); i!=genderList.end(); ++i)
>> result.push_back(eq(p,i->first) && eq(g,i->second) );
>> return result;
>> }
>>
>> What you talk dynamic relations is a transformation from a container to
>> a disjonction relation.
>> The user could implement a relation directly ensuring the unification.
>> E.g.
>>
>> struct gender_dyn : relation
>> ...
>> list<pair<string,string> > list_;
>> list<pair<string,string> >::iterator current_;
>>
>> bool operator(lref<string> p, lref<string> g) {
>> if (current_==list.end()) return false;
>> p= current_->first; // unification
>> g= current_->second; // unification
>> ++current_;
>> return true;
>> }
>>
>> bool operator(string const& p, lref<string> g) {
>> while (current_!=list.end() && p!=current_->first)
>> ++current_;
>> if (current_==list.end()) return false;
>> g= current_->second; // unification
>> ++current_;
>> return true;
>> }
>> ...
>>
>> This should be more efficient, ins't it?
>
>
> The goal of the example is only to demonstrate how to dynamically build
> the clauses in a relations. You can make this example more efficient with
> some work. For brevity, the existing example is re-used and implemented
> differently. Your solution is to define the relation imperatively as
> opposed to adding clauses dynamically. That is a valid alternative...
> although it requires more work it can often lead to efficiency gains.
Can you point me to the different implementation that is efficient?
> BTW: remember in your code above ... unification is not merely assignment.
I know that also. ;-)
> No need for inheritance either.
Grat. I just writo : relarion as I had not found the definition of the Concept behind relation on the tutorial? is it any functions returning bool and having lref parameters?
> It would roughly look as follows:
>
> struct gender_dyn : Coroutine {
> gender_dyn(lref<string> p, lref<string> g);
>
> bool operator() (void) {
> co_begin();
<snip>
> co_end();
> }
> };
Wow, are coroutines part of the library also? or is just an alternatives design?
Could you point to a complete example on the documentation?
If all the utilities you have given are already on the library it is time I read completly the documentation.
Thanks,
Vicente
_____________________
Vicente Juan Botet Escribá
http://viboes.blogspot.com/
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk