[castor] Interest in Logic Paradigm for C++ ?

Based on suggestions from some Boost community experts, I would like to gauge interest to see if there is broader interest for including the Castor library into Boost. In short, Castor's aim is to foster multiparadigm programming in C++ by supporting techniques from the Logic Paradigm. See below for a longer description. ============== Description: ============== Logic Paradigm (LP) is a general purpose declarative programming paradigm. It focuses on "what" to compute and not "how" to compute. Although LP has been well explored in Computer Science as a fundamental computational model, it remains unavailable for main stream software development due to lack of support in popular programming languages. Prolog is perhaps the most commonly known language among those that support LP. Castor takes a pure library approach (i.e. without language extensions) for introducing LP to C++. Instead of providing a Logic interpreter or evaluation engine in library form, Castor provides a few simple library primitives on which LP techniques can be supported. This approach allows a natural and deep integration of declarative code into the language and also provides the flexibility of freely combining Logic with the other paradigms such as OO, generics, functional etc. STL concepts like iterators, containers and streams can also be used in declarative code. For an introductory tutorial on LP in C++ and Castor please refer to http://mpprogramming.com/downloads/betaTutorial.pdf. Castor is intended to be a free standing library that depends only on the standard C++ library. It does not depend on Boost or other libraries. It is a pure header library. ============== Current State: ============== A stable 1.0 version has been available since 2008 on www.mpprogramming.com/cpp under the MIT license. Work on version 1.1 is in progress and an early beta is now available. Current efforts are directed largely towards making Castor a richer "standard library" for working with LP in C++. Castor was not originally targeted for Boost but more recently I have been giving it more serious consideration regarding inclusion into Boost. At the upcoming BoostCon 2010 I will be presenting 'Logic Paradigm for C++'. If there is interest, my thought is that feedback from the Boost review/submission process and modifications to satisfy other Boost requirements/guidelines will perhaps yield a 1.2 version that will become the real Boost candidate. Any help in this space will be much appreciated. ================== Links for Castor - v1.1 beta (ported to Gcc 4.4.1 and VC++ 2008) : ================== Library+docs: http://mpprogramming.com/downloads/prebeta-1.1.zip Individually downloadable documentation: Tutorial: http://mpprogramming.com/downloads/betaTutorial.pdf Reference Manual: http://mpprogramming.com/downloads/betaRefManual.pdf Design doc: http://mpprogramming.com/downloads/betaDesignDoc.pdf - Roshan Naik

Based on suggestions from some Boost community experts, I would like to gauge interest to see if there is broader interest for including the Castor library into Boost. In short, Castor's aim is to foster multiparadigm programming in C++ by supporting techniques from the Logic Paradigm. See below for a longer description.
I've been saying for years that Prolog is just a library :) I skimmed over the documentation, and I'm quite impressed. It seems like quite a nice library. I think it would be really cool to have something like this in Boost or at least associated with Boost. With the switch to git coming up this summer, building "companion" libraries might be a bit easier or more feasible. I think the biggest benefit for your library would be the peer review. Hopefully other people are interested too:) Andrew Sutton andrew.n.sutton@gmail.com

On Fri, Apr 30, 2010 at 1:31 AM, Andrew Sutton <andrew.n.sutton@gmail.com> wrote:
I think it would be really cool to have something like this in Boost or at least associated with Boost. With the switch to git coming up this summer, building "companion" libraries might be a bit easier or more feasible.
OT: I must have missed news that boost is going to switch to git. Could you provide some links on the rationale? -- Christoph

On Fri, Apr 30, 2010 at 7:30 AM, Christoph Heindl < christoph.heindl@gmail.com> wrote:
OT: I must have missed news that boost is going to switch to git. Could you provide some links on the rationale?
http://groups.google.co.uk/group/boost-developers-archive/browse_thread/thre...

On Fri, Apr 30, 2010 at 11:06 AM, Robert Jones <robertgbjones@gmail.com> wrote:
http://groups.google.co.uk/group/boost-developers-archive/browse_thread/thre...
thanks a lot Robert! -- Christoph

Robert Jones-2 wrote:
On Fri, Apr 30, 2010 at 7:30 AM, Christoph Heindl < christoph.heindl@gmail.com> wrote:
OT: I must have missed news that boost is going to switch to git. Could you provide some links on the rationale?
http://groups.google.co.uk/group/boost-developers-archive/browse_thread/thre...
I don't find nothing in this thread that let me think that Boost will migrate to Git this summer. Could you be more specific? Best, Vicente -- View this message in context: http://old.nabble.com/-castor--Interest-in-Logic-Paradigm-for-C%2B%2B----tp2... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Fri, Apr 30, 2010 at 1:56 PM, Vicente Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Robert Jones-2 wrote:
On Fri, Apr 30, 2010 at 7:30 AM, Christoph Heindl < christoph.heindl@gmail.com> wrote:
OT: I must have missed news that boost is going to switch to git. Could you provide some links on the rationale?
http://groups.google.co.uk/group/boost-developers-archive/browse_thread/thre...
I don't find nothing in this thread that let me think that Boost will migrate to Git this summer. Could you be more specific?
I can't I'm afraid - once you know that you know as much as I know. - Rob.

On Thu, 29 Apr 2010 17:31:04 -0600, Andrew Sutton <andrew.n.sutton@gmail.com> wrote:
Based on suggestions from some Boost community experts, I would like to gauge interest to see if there is broader interest for including the Castor library into Boost. In short, Castor's aim is to foster multiparadigm programming in C++ by supporting techniques from the Logic Paradigm. See below for a longer description.
I've been saying for years that Prolog is just a library :) I skimmed over the documentation, and I'm quite impressed. It seems like quite a nice library.
I think it would be really cool to have something like this in Boost or at least associated with Boost. With the switch to git coming up this summer, building "companion" libraries might be a bit easier or more feasible. I think the biggest benefit for your library would be the peer review.
Hopefully other people are interested too:)
Andrew Sutton andrew.n.sutton@gmail.com _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

On Thu, 29 Apr 2010 17:31:04 -0600, Andrew Sutton <andrew.n.sutton@gmail.com> wrote:
I think it would be really cool to have something like this in Boost or at least associated with Boost.
What is the difference between "having it in Boost" and "associated with Boost" ? -Roshan

I think it would be really cool to have something like this in Boost or at
least associated with Boost.
What is the difference between "having it in Boost" and "associated with Boost" ?
I'm not entirely sure. This might be a side-effect of moving to git/ryppl. It's conceivable to have larger, domain-specific libraries go through a review, but continue to be hosted, developed, and versioned outside the main Boost distribution. Purely speculation. Andrew Sutton andrew.n.sutton@gmail.com

On Thu, Apr 29, 2010 at 8:12 AM, Roshan Naik <roshan_naik@yahoo.com> wrote: [snip] I'm not at all up to speed on LP, so forgive me if I've missed the point! I can see that Castor is a splendid and useful library, entirely in its own right, but I'm not clear why you feel it's an appropriate candidate for inclusion in Boost. On reflection it comes down to the question of what Boost is. Do domain specific libraries of all sorts have a home here (for which I guess examples would include the BGL), or is Boost more about a general programming toolkit (for example Boost.Bind). I don't know the answer to that, not do I feel qualified to make any judgement. - Rob.

I'm not clear why you feel it's an appropriate candidate for inclusion in Boost.
On reflection it comes down to the question of what Boost is. Do domain specific libraries of all sorts have a home here (for which I guess examples would include the BGL), or is Boost more about a general programming toolkit (for example Boost.Bind). I don't know the answer to that, not do I feel qualified to make any judgement.
I've actually been thinking about this question (in general, not specifically for Castor) for a couple of months. There appear to be some natural partitions in the kinds of Boost libraries: system abstractions, general programming, programming paradigm, data structures & algorithms, scientific computing, DSELs, etc. It's not always obvious that these categories exist because Boost is so large, or which libraries fall into which categories. I think Castor definitely falls into the paradigm category, probably also in DS&A too -- especially if you make unification a top-level algorithm. An association with Boost, if not submission, would be a good thing. At least, that's what I think :) Andrew Sutton andrew.n.sutton@gmail.com

[Rob wrote:]
I can see that Castor is a splendid and useful library, entirely in its own right, but I'm not clear why you feel it's an appropriate candidate for inclusion in Boost.
On reflection it comes down to the question of what Boost is. Do domain specific libraries of all sorts have a home here (for which I guess examples would include the BGL), or is Boost more about a general programming toolkit (for example Boost.Bind). I don't know the answer to that, not do I feel qualified
The second paragraph on the main page of the Boost website states: "Boost libraries are intended to be widely useful, and usable across a broad spectrum of applications." In practice too, it does not appear to favor domain specific or general purpose libraries. -Roshan

On reflection it comes down to the question of what Boost is. Do domain specific libraries of all sorts have a home here (for which I guess examples would include the BGL), or is Boost more about a general programming toolkit (for example Boost.Bind). I don't know the answer to that, not do I feel qualified
The second paragraph on the main page of the Boost website states: "Boost libraries are intended to be widely useful, and usable across a broad spectrum of applications." In practice too, it does not appear to favor domain specific or general purpose libraries.
Is this an argument against including Castor as a Boost library? Boost is full of domain specific and general purpose (programming?) libraries. I'm not sure this is a valid argument. Andrew Sutton andrew.n.sutton@gmail.com

Hello, to me, Castor looks very interesting, and also very solid. It is strange to consider it as "domain specific", since it implements a general computational paradigm. C++ as a sort of open programming language would definitely profit by an inclusion of such general capabilities into a high-profile library like Boost. It's also not a big library, and headers-only, so should perfectly fit into Boost. Oliver On Sat, May 01, 2010 at 08:01:15AM -0400, Andrew Sutton wrote:
On reflection it comes down to the question of what Boost is. Do domain specific libraries of all sorts have a home here (for which I guess examples would include the BGL), or is Boost more about a general programming toolkit (for example Boost.Bind). I don't know the answer to that, not do I feel qualified
The second paragraph on the main page of the Boost website states: "Boost libraries are intended to be widely useful, and usable across a broad spectrum of applications." In practice too, it does not appear to favor domain specific or general purpose libraries.
Is this an argument against including Castor as a Boost library? Boost is full of domain specific and general purpose (programming?) libraries. I'm not sure this is a valid argument.
Andrew Sutton andrew.n.sutton@gmail.com _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Oliver Kullmann wrote:
Hello,
to me, Castor looks very interesting, and also very solid. It is strange to consider it as "domain specific", since it implements a general computational paradigm. C++ as a sort of open programming language would definitely profit by an inclusion of such general capabilities into a high-profile library like Boost.
It's also not a big library, and headers-only, so should perfectly fit into Boost.
Oliver
I share the point of view of Oliver : I don't see how this could be domain specific. The beta-tutorial is very well written and promising. Best regards, Pierre Morcello

On Sat, 01 May 2010 06:01:15 -0600, Andrew Sutton <andrew.n.sutton@gmail.com> wrote:
Is this an argument against including Castor as a Boost library?
Not at all. I was trying to pointing out to Robert that Boost is interested in all kinds of libraries. -Roshan

Not at all. I was trying to pointing out to Robert that Boost is interested in all kinds of libraries.
I must have misread the previous post. I did reply before my morning coffee, so I may not have understood :) My apologies. I guess the next step is requesting that Castor be added to review queue. Andrew Sutton andrew.n.sutton@gmail.com

Andrew Sutton <andrew.n.sutton@gmail.com> wrote:
I guess the next step is requesting that Castor be added to review queue.
Is that right ? My understanding was that the next step is to upload it into Boost Vault where it will simmer for a while. I know it will surely need some massaging to satisfy Boost guidelines and policies. I am not too familiar with this process other than whats mentioned on the Boost website about this and Robert Ramey's "Making a Boost Library". It would be wonderful if someone more familiar with this process can work/discuss these issues offline with me. -Roshan

I guess the next step is requesting that Castor be added to review queue.
Is that right ? My understanding was that the next step is to upload it into Boost Vault where it will simmer for a while. I know it will surely need some massaging to satisfy Boost guidelines and policies.
I am not too familiar with this process other than whats mentioned on the Boost website about this and Robert Ramey's "Making a Boost Library". It would be wonderful if someone more familiar with this process can work/discuss these issues offline with me.
It might be right. I'm pretty sure we've reviewed libraries that were hosted outside of Boost before. But I'm not Robert, so I won't guarantee that :) Andrew Sutton andrew.n.sutton@gmail.com

Seems like there is sufficient interest in Castor. My understanding from the online documentation of the Boost submission process is that the next step is to upload it to Boost Vault. Whats the process for uploading to the Boost vault ? I don't see any mention of this. - Roshan

Hello Roshan, only my 2 cents... I would first spend a little work in bringing the Castor library into line with the typically boost libraries. I.e. namespace, directory layout, test cases and example programs (incl. boost build system). Additionally, I would take a look at the documentation of some of the recent successful newcomers. It might be worth to adapt your documentation to the style of these libraries. Before requesting a review of the library, I would give the library some time in the boost space. Be prepared to give way of some of your own judgments and habits. Search for discussion of the library's interface and implementation. You actually did get some fairly great response in a short period of time. Did you have tracking some of the other reviews? It is very instructive to analyze some of them. I definitely would like to see a LP library in boost and Castor seems very promissing. Best, Johannes

Before requesting a review of the library, I would give the library some time in the boost space.
Hi Johannes, Right. I do not intend to request a review anytime soon. All those items on your list and more need to done before the library is up for review. I don't think there is any implied requirement to go for a review as soon as this is uploaded into Boost Vault. I just talked to Jeff Garland today at BoostCon and confirmed this. He also mentioned that even uploading the library to the Vault is optional if you already have a place to host the preliminary bits. I wish there was book "Boost Library Submittal for Dummies". I am a bit overwhelmed at the number of things that I need to wrap my head around ... the culture, documentation tools, testing infrastructure, branching model, build system, other boost libraries, how to take beatings ... and God knows what else (the unknown unknowns). -Roshan

I am not too familiar with this process other than whats mentioned on the Boost website about this and Robert Ramey's "Making a Boost Library".
Interesting, very useful, thanks. Question, why does the Boost website does not link to this article? I think it would be well placed on the page <http://www.boost.org/development/submissions.html> Here is the link: <http://www.rrsd.com/software_development/boost/oopsla05.pdf> Regards, Barend

If I had nothing else to do, I would have a LOT more to say about this subject. Maybe someday I will. Robert Ramey Barend Gehrels wrote:
I am not too familiar with this process other than whats mentioned on the Boost website about this and Robert Ramey's "Making a Boost Library". Interesting, very useful, thanks. Question, why does the Boost website does not link to this article? I think it would be well placed on the page <http://www.boost.org/development/submissions.html>
Here is the link: <http://www.rrsd.com/software_development/boost/oopsla05.pdf>
Regards, Barend
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

"Robert Ramey" <ramey@rrsd.com> schrieb im Newsbeitrag news:hrmq73$cf1$1@dough.gmane.org...
If I had nothing else to do, I would have a LOT more to say about this subject. Maybe someday I will.
I would be really interested in your position. Regards, Johannes

_____________________ Vicente Juan Botet Escribá http://viboes.blogspot.com/ ----- Original Message ----- From: "Robert Jones" <robertgbjones@gmail.com> To: <boost@lists.boost.org> Sent: Friday, April 30, 2010 10:49 AM Subject: Re: [boost] [castor] Interest in Logic Paradigm for C++ ?
On Thu, Apr 29, 2010 at 8:12 AM, Roshan Naik <roshan_naik@yahoo.com> wrote: [snip]
I'm not at all up to speed on LP, so forgive me if I've missed the point! I can see that Castor is a splendid and useful library, entirely in its own right, but I'm not clear why you feel it's an appropriate candidate for inclusion in Boost.
On reflection it comes down to the question of what Boost is. Do domain specific libraries of all sorts have a home here (for which I guess examples would include the BGL), or is Boost more about a general programming toolkit (for example Boost.Bind). I don't know the answer to that, not do I feel qualified to make any judgement.
Boost includes already domain specific libraries as: Math, BGL, uBLAS, GIL and Spirit, the new libraries Geometry, Polygon, UUID and other proposed as Static Size Linear Algebra, Lexer, Join. Do you think that some of these libraries should't be in Boost because they are domain specific? I don't see how a library that propose unification and backtracking (LP) could not be considered for review. Why you feel it isn't an appropriate candidate for inclusion in Boost? Best, _____________________ Vicente Juan Botet Escribá http://viboes.blogspot.com/

Hi Roshan, Roshan Naik wrote:
Based on suggestions from some Boost community experts, I would like to gauge interest to see if there is broader interest for including the Castor library into Boost. I'm very interested. I've used Prolog before and I've looked at Castor before, and I think it is a very useful addition to Boost.
Thanks, Barend

Count me interested a lot... Best, Johannes "Roshan Naik" <roshan_naik@yahoo.com> schrieb im Newsbeitrag news:007b01cae76b$4472eda0$cd58c8e0$@com...
Based on suggestions from some Boost community experts, I would like to gauge interest to see if there is broader interest for including the Castor library into Boost.

On Thu, Apr 29, 2010 at 1:12 AM, Roshan Naik <roshan_naik@yahoo.com> wrote:
Based on suggestions from some Boost community experts, I would like to gauge interest to see if there is broader interest for including the Castor library into Boost. In short, Castor's aim is to foster multiparadigm programming in C++ by supporting techniques from the Logic Paradigm. See below for a longer description.
============== Description: ==============
Logic Paradigm (LP) is a general purpose declarative programming paradigm. It focuses on "what" to compute and not "how" to compute. Although LP has been well explored in Computer Science as a fundamental computational model, it remains unavailable for main stream software development due to lack of support in popular programming languages. Prolog is perhaps the most commonly known language among those that support LP. Castor takes a pure library approach (i.e. without language extensions) for introducing LP to C++.
Instead of providing a Logic interpreter or evaluation engine in library form, Castor provides a few simple library primitives on which LP techniques can be supported. This approach allows a natural and deep integration of declarative code into the language and also provides the flexibility of freely combining Logic with the other paradigms such as OO, generics, functional etc. STL concepts like iterators, containers and streams can also be used in declarative code.
For an introductory tutorial on LP in C++ and Castor please refer to http://mpprogramming.com/downloads/betaTutorial.pdf.
Castor is intended to be a free standing library that depends only on the standard C++ library. It does not depend on Boost or other libraries. It is a pure header library.
============== Current State: ============== A stable 1.0 version has been available since 2008 on www.mpprogramming.com/cpp under the MIT license. Work on version 1.1 is in progress and an early beta is now available. Current efforts are directed largely towards making Castor a richer "standard library" for working with LP in C++.
Castor was not originally targeted for Boost but more recently I have been giving it more serious consideration regarding inclusion into Boost. At the upcoming BoostCon 2010 I will be presenting 'Logic Paradigm for C++'. If there is interest, my thought is that feedback from the Boost review/submission process and modifications to satisfy other Boost requirements/guidelines will perhaps yield a 1.2 version that will become the real Boost candidate. Any help in this space will be much appreciated.
================== Links for  Castor - v1.1 beta (ported to Gcc 4.4.1 and VC++ 2008) : ==================
  Library+docs: http://mpprogramming.com/downloads/prebeta-1.1.zip
Individually downloadable documentation:   Tutorial: http://mpprogramming.com/downloads/betaTutorial.pdf   Reference Manual: http://mpprogramming.com/downloads/betaRefManual.pdf
  Design doc: http://mpprogramming.com/downloads/betaDesignDoc.pdf
Ignoring the rest of the comments in this thread for now, I have some comments. I like the whole design of it, some limitations seem overcome by some Boost libraries though. However, I notice a *lot* of overlap with Boost.Phoenix, it kind of seems like a continuation layer on top of Boost.Phoenix, and it probably could in fact be implement as a layer of Boost.Phoenix (Boost.Phoenix is made up of layers of functionality, and a logic layer makes sense). Boost.Phoenix is a lazy evaluation framework for C++. When it is finished being ported to Boost.Proto for Boost.Phoenix 3, I think a Caster-style Logic layer would make a lot of sense, and would allow it to blend far more easily into the rest of boost while getting all the functionality of Boost.Phoenix (including the calling style fixes that Boost.Phoenix uses, val/ref's and such), along with pure lazy *type* inference too (which Caster does not do at all, not a major limitation, but one that could cause more code to be created at times then necessary), which would solve the whole list/vector thing the tutorial talks about (along with supporting any generic container transparently). Have you thought about this? Overall though I am quite impressed, I could see uses for this to simplify scaffolding in many ways, just to start with.

On Sun, 02 May 2010 20:40:39 -0600, OvermindDL1 <overminddl1@gmail.com> wrote:
However, I notice a *lot* of overlap with Boost.Phoenix, it kind of seems like a continuation layer on top of Boost.Phoenix, and it probably could in fact be implement as a layer of Boost.Phoenix (Boost.Phoenix is made up of layers of functionality, and a logic layer makes sense). Boost.Phoenix is a lazy evaluation framework for C++. When it is finished being ported to Boost.Proto for Boost.Phoenix 3,
I think a Caster-style Logic layer would make a lot of sense, and would allow it to blend far more easily into the rest of boost while getting all the functionality of Boost.Phoenix (including the calling style fixes that Boost.Phoenix uses, val/ref's and such), along with pure lazy *type* inference too (which Caster does not do at all, not a major limitation, but one that could cause more code to be created at times then necessary), which would solve the whole list/vector thing the tutorial talks about (along with supporting any generic container transparently).
Have you thought about this?
Nope! I have restrained from introducing any cross library dependencies in an effort to keep it a standalone library. I am very keen on ensuring Castor continues to be distributable & usable as a standalone library even if included into Boost. However your suggestion interests me. From what I read, it seems that it might be possible to "peel off" just the necessary amount of Phoenix without dragging in all of Phoenix or rest of Boost. This sounds appealing to me since I want to ensure : (Benefits to end users + Benefits of code reduction in Castor's internals) > disadvantages of depending on another library (Phoenix) Often these secondary libraries are too big (mcuh bigger than all of Castor) and in turn depend on other (Boost) libraries. Castor 1.0 is a really small library (under 5k LOC). The simple lambda support in Castor 1.0 totals to about 300 lines of code... compare that to relying on the "all powerful" boost.lambda which is about 14k LOC. Wasn't worth it. I would like to investigate your suggestion further ... perhaps I can exchange emails with you offline on this topic to orient myself in the right direction. -Roshan

----- Original Message ----- From: "Roshan" <roshan_naik@yahoo.com> To: <boost@lists.boost.org> Sent: Monday, May 03, 2010 11:20 PM Subject: Re: [boost] [castor] Interest in Logic Paradigm for C++ ?
On Sun, 02 May 2010 20:40:39 -0600, OvermindDL1 <overminddl1@gmail.com> wrote:
However, I notice a *lot* of overlap with Boost.Phoenix, it kind of seems like a continuation layer on top of Boost.Phoenix, and it probably could in fact be implement as a layer of Boost.Phoenix (Boost.Phoenix is made up of layers of functionality, and a logic layer makes sense). Boost.Phoenix is a lazy evaluation framework for C++. When it is finished being ported to Boost.Proto for Boost.Phoenix 3,
I think a Caster-style Logic layer would make a lot of sense, and would allow it to blend far more easily into the rest of boost while getting all the functionality of Boost.Phoenix (including the calling style fixes that Boost.Phoenix uses, val/ref's and such), along with pure lazy *type* inference too (which Caster does not do at all, not a major limitation, but one that could cause more code to be created at times then necessary), which would solve the whole list/vector thing the tutorial talks about (along with supporting any generic container transparently).
Have you thought about this?
Nope! I have restrained from introducing any cross library dependencies in an effort to keep it a standalone library. I am very keen on ensuring Castor continues to be distributable & usable as a standalone library even if included into Boost.
However your suggestion interests me. From what I read, it seems that it might be possible to "peel off" just the necessary amount of Phoenix without dragging in all of Phoenix or rest of Boost. This sounds appealing to me since I want to ensure :
(Benefits to end users + Benefits of code reduction in Castor's internals) > disadvantages of depending on another library (Phoenix)
Often these secondary libraries are too big (mcuh bigger than all of Castor) and in turn depend on other (Boost) libraries. Castor 1.0 is a really small library (under 5k LOC). The simple lambda support in Castor 1.0 totals to about 300 lines of code... compare that to relying on the "all powerful" boost.lambda which is about 14k LOC. Wasn't worth it.
Hi, this is no the first time some one want to introduce a library in Boost but don't want to use nothing of Boost; even if the abstraction already exist in Boost. Whether a library I use is about 1KLOC or 100KLOC it is not important to me, if the service the library provides is what I need. What kind of users do you want to preserv with a standalone library that will not use your library if it depends on Boost? Best, Vicente

On Mon, May 3, 2010 at 5:05 PM, vicente.botet <vicente.botet@wanadoo.fr> wrote:
----- Original Message ----- From: "Roshan" <roshan_naik@yahoo.com> To: <boost@lists.boost.org> Sent: Monday, May 03, 2010 11:20 PM Subject: Re: [boost] [castor] Interest in Logic Paradigm for C++ ?
Often these secondary libraries are too big (mcuh bigger than all of Castor) and in turn depend on other (Boost) libraries. Castor 1.0 is a really small library (under 5k LOC). The simple lambda support in Castor 1.0 totals to about 300 lines of code... compare that to relying on the "all powerful" boost.lambda which is about 14k LOC. Wasn't worth it.
Hi,
this is no the first time some one want to introduce a library in Boost but don't want to use nothing of Boost; even if the abstraction already exist in Boost. Whether a library I use is about 1KLOC or 100KLOC it is not important to me, if the service the library provides is what I need.
What kind of users do you want to preserv with a standalone library that will not use your library if it depends on Boost?
I agree, the size of the library matters not to me (as long as it compiles into very tight assembly, I do not care about compile times either, I always have other tasks to be doing). And if you really want to package it externally, Boost.BCP can easily do that.

On Mon, 03 May 2010 22:10:21 -0600, OvermindDL1 <overminddl1@gmail.com> wrote:
On Mon, May 3, 2010 at 5:05 PM, vicente.botet <vicente.botet@wanadoo.fr> wrote:
Whether a library I use is about 1KLOC or 100KLOC it is not important to me, if the service the library provides is what I need.
What kind of users do you want to preserv with a standalone library that will not use your library if it depends on Boost?
I agree, the size of the library matters not to me (as long as it compiles into very tight assembly, I do not care about compile times
As a library author, I deeply care when imposing such requirements on users. There was an earlier post of an existing user who expressed the desire to have it standalone. http://old.nabble.com/Re%3A--castor--Interest-in-Logic-Paradigm-for-C%2B%2B-... Concern that Boost has become a giant hair ball of intertwined libraries is not limited to a few people. Bjarne mentioned this as the reason for not introducing Boost libraries to his students during a casual conversation at a conference. Introducing a massive library collection (for the sake of a tiny library) into a sophisticated source control/build environments of large corporations is a big deal. I am OK with introducing such coupling between libraries provided the benefits outweigh the costs to consumers of the library. I looked at Phoenix briefly. The headers in the core directory is about 1k LOC ... but it seems to depend (at least) on mpl... which is a giant. Another problem is, once you depend on one library, there is no control on how many dependencies that library itself will drag in (which can change with every release). Too risky. - Roshan

----- Original Message ----- From: "Roshan" <roshan_naik@yahoo.com> To: <boost@lists.boost.org> Sent: Tuesday, May 04, 2010 7:32 PM Subject: Re: [boost] [castor] Interest in Logic Paradigm for C++ ?
On Mon, 03 May 2010 22:10:21 -0600, OvermindDL1 <overminddl1@gmail.com> wrote:
On Mon, May 3, 2010 at 5:05 PM, vicente.botet <vicente.botet@wanadoo.fr> wrote:
Whether a library I use is about 1KLOC or 100KLOC it is not important to me, if the service the library provides is what I need.
What kind of users do you want to preserv with a standalone library that will not use your library if it depends on Boost?
I agree, the size of the library matters not to me (as long as it compiles into very tight assembly, I do not care about compile times
As a library author, I deeply care when imposing such requirements on users. There was an earlier post of an existing user who expressed the desire to have it standalone. http://old.nabble.com/Re%3A--castor--Interest-in-Logic-Paradigm-for-C%2B%2B-...
I understand he because he uses already your library in sandalone mode. I dont think people using Boost will care if your library is standalone or not.
Concern that Boost has become a giant hair ball of intertwined libraries is not limited to a few people. Bjarne mentioned this as the reason for not introducing Boost libraries to his students during a casual conversation at a conference. Introducing a massive library collection (for the sake of a tiny library) into a sophisticated source control/build environments of large corporations is a big deal. I am OK with introducing such coupling between libraries provided the benefits outweigh the costs to consumers of the library.
So why is the advantage for you to include the library on Boost? I'm not suggesting to you to use any Boost libraries, atleast not yet, but the fact you don't want to use any at all to maintain your library standalone trouble me a little bit. On how many compiler, platforms your library has been ported? You don't think that you will need at least the Config library to port to all the platforms Boost run on? Best, Vicente

Roshan wrote:
On Mon, 03 May 2010 22:10:21 -0600, OvermindDL1
What kind of users do you want to preserv with a standalone library that will not use your library if it depends on Boost?
I agree, the size of the library matters not to me (as long as it compiles into very tight assembly, I do not care about compile times
As a library author, I deeply care when imposing such requirements on users. There was an earlier post of an existing user who expressed the desire to have it standalone. http://old.nabble.com/Re%3A--castor--Interest-in-Logic-Paradigm-for-C%2B%2B-...
Concern that Boost has become a giant hair ball of intertwined libraries is not limited to a few people. Bjarne mentioned this as the reason for not introducing Boost libraries to his students during a casual conversation at a conference. Introducing a massive library collection (for the sake of a tiny library) into a sophisticated source control/build environments of large corporations is a big deal. I am OK with introducing such coupling between libraries provided the benefits outweigh the costs to consumers of the library.
So it's a good idea to repeat functionality in more than one place? That is it's a good idea for castor to include equivalent functionality that already exists in boost. This effectively increases the total amount of code being dealt with rather than decreasing it. If a library (or any code) is simpler and smaller because it includes a lot of code all ready existent then shouldn't ALL code (including boost) copy in the functionality from all the libaries it uses. Basically, the idea that a library is simpler because it doesn't include other libraries doesn't make sense when carried to it's logical conclusion. If you really believe this, then you'll have to conclude that no one will want to use your library either. Of course if there is a specific problem with some boost libraries or boost libraries in particular, that's another issue entirely. And an interesting one. In my professional life, I often come accross programmers who shy away from boost libraries. They'll spend weeks (of their employer's time and money) to re-create some small functionality which is already in some library and could be included with just 2 days of study. Which is the problem. Boost libraries aspire to be more generic and that means a higher level of abstraction. This means that it takes a lot more effort to use the library than it first appears. The idea of a library makes it sound like "just drop it in" but then it turns out one has to spend a couple of days figuring it out and it seems easier just to "roll your own". Of course it isn't but that's not apparent even after the fact. Anyway. I'm very intrigued with this library idea. Robert Ramey

On Tue, 04 May 2010 16:02:39 -0600, Robert Ramey <ramey@rrsd.com> wrote:
If you really believe this, then you'll have to conclude that no one will want to use your library either.
No, I am just saying its a important to think twice before replacing a 100 lines of invisible internals with several thousand lines from another library. The issue is not as simple as "don't ever use another library". As part of the Boost submittal process I will have to investigate where it makes sense to introduce/avoid such dependencies. -Roshan

On Tue, May 4, 2010 at 2:21 PM, Roshan <roshan_naik@yahoo.com> wrote:
On Tue, 04 May 2010 16:02:39 -0600, Robert Ramey <ramey@rrsd.com> wrote:
If you really believe this, then you'll have to conclude that no one will want to use your library either.
No, I am just saying its a important to think twice before replacing a 100 lines of invisible internals with several  thousand lines from another library. The issue is not as simple as "don't ever use another library".
However these libraries are not used lightly, they are well tested, very functional, etc.... On many other points in this thread =================================== As for Iterators, they can easily return a tuple of values, not just a single. Why not a Range concept? Many of the issues people and you have pointed out could be solved in a Boost.Phoenix style interface instead. As an example, in pure pseudo-code, this should be quite possible: auto f = arg1=="Sam" && arg2=="Mary" //fact 1 || arg1=="Denise") && arg2=="Mary" //fact 2 || arg1=="Sam") && arg2=="Frank" //fact 3 || arg1=="Denise") && arg2=="Frank" //fact 4 || arg1=="Frank") && arg2=="Gary" //fact 5 ; // Loop over all for(auto r = f(any,any); r; ++r) { cout << r.get<0>() << ":" << r.get<1>() << endl; } /* Prints: Sam:Mary Denise:Mary Sam:Frank Denis:Frank Frank:Gary */ // Loop over all of Sam's parents: for(auto r = f("Sam",any); r; ++r) { cout << r.get<0>() << ":" << r.get<1>() << endl; } /* Prints: Sam:Mary Sam:Frank */ // Test if Sam is child of Mary auto r = f("Sam", "Mary"); cout << r.get<0>() << " is child of " << r.get<1>() << " is " << boolalpha << r << endl; /* Prints: Sam is child of Mary is true */ 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.

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

On Mon, May 3, 2010 at 3:20 PM, Roshan <roshan_naik@yahoo.com> wrote:
On Sun, 02 May 2010 20:40:39 -0600, OvermindDL1 <overminddl1@gmail.com> wrote:
However, I notice a *lot* of overlap with Boost.Phoenix, it kind of seems like a continuation layer on top of Boost.Phoenix, and it probably could in fact be implement as a layer of Boost.Phoenix (Boost.Phoenix is made up of layers of functionality, and a logic layer makes sense). Â Boost.Phoenix is a lazy evaluation framework for C++. Â When it is finished being ported to Boost.Proto for Boost.Phoenix 3,
I think a Caster-style Logic layer would make a lot of sense, and would allow it to blend far more easily into the rest of boost while getting all the functionality of Boost.Phoenix (including the calling style fixes that Boost.Phoenix uses, val/ref's and such), along with pure lazy *type* inference too (which Caster does not do at all, not a major limitation, but one that could cause more code to be created at times then necessary), which would solve the whole list/vector thing the tutorial talks about (along with supporting any generic container transparently).
Have you thought about this?
Nope! I have restrained from introducing any cross library dependencies in an effort to keep it a standalone library. I am very keen on ensuring Castor continues to be distributable & usable as a standalone library even if included into Boost.
With the use of Boost.BCP, it is very simple to take the parts of boost you want and wrap it all up into a standalone project, it handles what requirements and all. On Mon, May 3, 2010 at 3:20 PM, Roshan <roshan_naik@yahoo.com> wrote:
However your suggestion interests me. From what I read, it seems that it might be possible to "peel off" just the necessary amount of Phoenix without dragging in all of Phoenix or rest of Boost. This sounds appealing to me since I want to ensure :
Boost.Phoenix is very powerful, and as someone else said in a different thread, its core is only about 90 lines of code (although that will be more once it is ported to Boost.Proto, but it will be even vastly more powerful then). The way it is designed is in layers (see its documentation www.boost.org/doc/libs/release/libs/spirit/phoenix/ , it has a whole picture and all, nice pretty examples), and any part only relies on pieces below it, it does not rely on any higher part, nor on any part on the same level, and yet they all inter-operate wonderfully. Caster could be such a part on a layer. And as stated, using Boost.BCP, you can rip out the libraries it needs, then you can manually trim them down (or another script) if you did not want to include all of Phoenix for whatever reason. On Mon, May 3, 2010 at 3:20 PM, Roshan <roshan_naik@yahoo.com> wrote:
(Benefits to end users + Benefits of code reduction in Castor's internals) Â > disadvantages of depending on another library (Phoenix)
Often these secondary libraries are too big (mcuh bigger than all of Castor) and in turn depend on other (Boost) libraries. Castor 1.0 is a really small library (under 5k LOC). The simple lambda support in Castor 1.0 totals to about 300 lines of code... compare that to relying on the "all powerful" boost.lambda which is about 14k LOC. Wasn't worth it.
Boost.Phoenix internals are also *very* small, just some parts of it are bigger then others, all depends on the functionality you need. The new version currently being made will be a bit bigger as its base since it will use Boost.Proto as the metafunction handler, but it will get a even more power by this move. On Mon, May 3, 2010 at 3:20 PM, Roshan <roshan_naik@yahoo.com> wrote:
I would like to investigate your suggestion further ... perhaps I can exchange emails with you offline on this topic to orient myself in the right direction.
I am not the right person for this, just a user of Boost.Phoenix (well, I have made a few customized parts for my own use, but still, just a user), Joel De Guzman is, but he is *busy*. It is always best to talk about these things in the public list anyway as others can learn from it as well. If you wish we can talk privately, but publicly is always better.

On Thu, Apr 29, 2010 at 2:12 AM, Roshan Naik <roshan_naik@yahoo.com> wrote:
Based on suggestions from some Boost community experts, I would like to gauge interest to see if there is broader interest for including the Castor library into Boost.
This library looks really promising! I look forward to using it. I have some suggestions about the interface and documentation. * The semantics of generative queries strike me as wonky. I can see the appeal of assigning the result to an uninitialized argument, when there can only be exactly one result returned. However, there may be 0, 1, or N. That alone lessens the appeal of returning the results in the argument. Moreover, you're requiring users to then query the actual result relation to see if it's okay to dereference the lref<> parameter to get at its result. Then, you have each call to relation::operator() act as a loop iteration, complete with assignment to the lref<>, and even resetting the lref<> to an uninitialized state. And now my head hurts. ;) Since all of this is implicit, someone reading my code, or myself in a year and a half, will probably be left scratching his head. Further, at the call site: relation franksChildren = father("Frank", c); How do I know if this is semantically an assertion or a generative query, when I'm reading someone else's code and trying to understand it? I have to know a lot more context than I'd like. I have to look for all possible places that "c" might come from; whether none, some, or all of them are uninitialized; and which are and which aren't. So, instead of: lref<string> c; int count=0; relation franksChildren = father("Frank", c); while( franksChildren() ) { ++count; cout << *c << " is Frank's child\n"; } // c is now back to its uninitialized state cout << "Frank has " << count << " children"; How about: // Maybe "any_lref" is a weak name, but you get my point. Provide a tag type // and use it to make assertion-queries explicit. relation franksChildren = father("Frank", any_lref); for(relation::const_iterator it = franksChildren.begin(); it != franksChildren.end(); ++it) { cout << *it << " is Frank's child\n"; } cout << "Frank has " << franksChildren.size() << " children"; Or, in the style of Boost.ForEach or the upcoming standard: relation franksChildren = father("Frank", any_lref); for (const std::string& child : franksChildren) { cout << child << " is Frank's child\n"; } cout << "Frank has " << franksChildren.size() << " children"; * The way dynamic relations are constructed seems needlessly at odds with the way static relations are contructed. Instead of: list<pair<string,string> > genderList = ...; 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; } How about: relation gender_dyn(lref<string> p, lref<string> g) { relation result; list<pair<string,string> >::iterator i; for( i=genderList.begin(); i!=genderList.end(); ++i) result |= eq(p,i->first) && eq(g,i->second); return result; } ... and you handle the construction of Disjunctions/Conjunctions/Whatevers for me, under the covers? * The asymmetry between the use of && and || with ^ is a little bothersome, especially considering the desirability of using &=, |=, and ^= when building relations dynamically. Could you use & and | instead of && and ||? This would also remove the need for extra parentheses in some cases, since the precendences will be more natural. * What is the rationale behind providing both C++-style iterator iteration and head/tail iteration? Are there some cases where the former is more useful than the latter, *and* some other cases where the latter is more useful than the former? If not, could you just standardize on one approach? * I find at least part of the interface to sequence to be confusing. When reading this: relation r = sequence(lrl)(lri)(v.begin(), v.end()) (3); a newcomer to your library will certainly be completely lost. * While I like the use of operator^() to provide cut-like effects, it shouldn't be described as XOR as you're using it. XOR has pretty different semantics. For one, since XOR evaluates to true when its operands are unequal, it can't do short-circuiting any more than the equals relation can. * Can eq_f(), eq_mf() just go away, in favor of using std::bind/tr1::bind instead? You could just provide an overload if eq() that takes a std::function/tr1::function as its second parameter. * What were the limitations that caused you to retain predicate()? I can see how you might still need it in some situations, but most of the time I'd like to use my bool functions/function objects directly instead. Some editorial notes: * In 2.7 Inline Logic Reference Expressions, I don't think you meant to say: multiply(sq,n,n) && multiply(cu,sq,n)( ); Shouldn't it be: (multiply(sq,n,n) && multiply(cu,sq,n))( ); ? * Also in that section, you introduce predicate() by using it. It would be better to introduce predicate() first, or at least to make it clear that it's a library function, and will be explained more fully in section 4. This comment applies universally, since this seems to happen somewhat frequently in the documentation. Zach

On Tue, 04 May 2010 10:06:39 -0600, Zach Laine <whatwasthataddress@gmail.com> wrote:
On Thu, Apr 29, 2010 at 2:12 AM, Roshan Naik <roshan_naik@yahoo.com> wrote:
Based on suggestions from some Boost community experts, I would like to gauge interest to see if there is broader interest for including the Castor library into Boost.
This library looks really promising! I look forward to using it. I have some suggestions about the interface and documentation.
* The semantics of generative queries strike me as wonky. I can see the appeal of assigning the result to an uninitialized argument, when there can only be exactly one result returned. However, there may be 0, 1, or N. That alone lessens the appeal of returning the results in the argument. Moreover, you're requiring users to then query the actual result relation to see if it's okay to dereference the lref<> parameter to get at its result.
There is no requirement to inspect the lref. If evaluation of the relation succeeded.. the lref will be initialized. The idea that a relation can have 0 or more values/solutions is embedded in the theoretical definition relation. It is not a Castor concept. It is fundamental to this paradigm. I will being talking a bit about the concept of a "relation" and how it relates to concept of a "function" in my BoostCon talk. Most other ideas such as "direction-less" or "bi-directional" arguments merely follows from it.
Then, you have each call to relation::operator() act as a loop iteration, complete with assignment to the lref<>, and even resetting the lref<> to an uninitialized state.
And now my head hurts. ;)
Since all of this is implicit, someone reading my code, or myself in a year and a half, will probably be left scratching his head.
Having been a traditional programmer, my head hurt too when I encountered this paradigm. Give yourself some time to settle with it.
Further, at the call site:
relation franksChildren = father("Frank", c);
How do I know if this is semantically an assertion or a generative query, when I'm reading someone else's code and trying to understand it? I have to know a lot more context than I'd like. I have to look for all possible places that "c" might come from; whether none, some, or all of them are uninitialized; and which are and which aren't.
It is neither an assertion or a generative query. franksChildren is also a relation (like any other) which can be used to assert or generate. It is merely constraining the first argument to the father relation. You read as "Frank is father of c".
So, instead of:
lref<string> c; int count=0; relation franksChildren = father("Frank", c); while( franksChildren() ) { ++count; cout << *c << " is Frank's child\n"; } // c is now back to its uninitialized state cout << "Frank has " << count << " children";
How about:
// Maybe "any_lref" is a weak name, but you get my point. Provide a tag type // and use it to make assertion-queries explicit. relation franksChildren = father("Frank", any_lref); for(relation::const_iterator it = franksChildren.begin(); it != franksChildren.end(); ++it) { cout << *it << " is Frank's child\n"; } cout << "Frank has " << franksChildren.size() << " children";
Or, in the style of Boost.ForEach or the upcoming standard:
relation franksChildren = father("Frank", any_lref); for (const std::string& child : franksChildren) { cout << child << " is Frank's child\n"; } cout << "Frank has " << franksChildren.size() << " children";
Good question. There is a fundamental issue with the iterator/enumerator model which makes it unsuitable. The key difference is that in the iterator model divides the following into separate steps: 1) "is there more solutions" : begin()!=end() 2) "get me next solution" : operator ++ and you basically repetitively ask "is there more" and if yes.. "compute it". In many cases this is ok. But in general you cannot expect that it is possible to answer the "is there more" question without actually performing the computation to see if there is more. It may sound a bit like the halting problem. The model used in the logic paradigm is to repetitively ask "get me the next solution if there is one". The two steps are combined into one. The suggested syntax : for (const std::string& child : franksChildren) { .. } wont scale when enumerating with father(f,c) where both f and c are not initialized. But you could use this syntax if it makes any difference : for( relation franksChildren = father("Frank", c); franksChildren(); ) { ... }
* The way dynamic relations are constructed seems needlessly at odds with the way static relations are contructed. Instead of:
list<pair<string,string> > genderList = ...;
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; }
How about:
relation gender_dyn(lref<string> p, lref<string> g) { relation result; list<pair<string,string> >::iterator i; for( i=genderList.begin(); i!=genderList.end(); ++i) result |= eq(p,i->first) && eq(g,i->second); return result; }
The motivating issue for Disjunctions/Conjunctions/ExDisjuntions is that this statement is not allowed: relation result; // must be initialized As a relation must be defined. But this is semantically different: Disjunctions d; // OK This represents a collection of empty disjunctive clauses and evaluates to false if there aren't any. I am toying with this idea of +=. relation gender_dyn(lref<string> p, lref<string> g) { Disjuntions result; for( ... ) result += eq(p,i->first) && eq(g,i->second); return result; } The reason it was initially not implemented that way was because there is push_front() and push_back() methods for dynamic relations. The &= or |= operators do not have a symmetric equivalents to prepend. It now appears that push_front() is used much less in practice.. so I am thinking it may be worth it to simplify the syntax for the common push_back case with +=.
* The asymmetry between the use of && and || with ^ is a little bothersome, especially considering the desirability of using &=, |=, and ^= when building relations dynamically. Could you use & and | instead of && and ||?
In retrospect, I would like to have used & and | instead of && and ||. But I think its too late now. For this case, += can be used for push_back() instead of three different ones.
This would also remove the need for extra parentheses in some cases, since the precendences will be more natural.
indeed.. thats the main reason for the bitwise operators over the logicals. But, the precedence issue is true when clauses are specified in conjunctive normal form ... which happens to be common in examples in the tutorial.
* What is the rationale behind providing both C++-style iterator iteration and head/tail iteration? Are there some cases where the former is more useful than the latter, *and* some other cases where the latter is more useful than the former? If not, could you just standardize on one approach?
* I find at least part of the interface to sequence to be confusing. When reading this:
relation r = sequence(lrl)(lri)(v.begin(), v.end()) (3);
a newcomer to your library will certainly be completely lost.
I do not recommend using sequence() anymore. It has become too complex internally than I hoped it would. Its purpose would probably be more obvious to people with Prolog background... to do some pattern matching style unification for lists. In the context of LP within C++, I currently feel that such a mechanism is not as useful as it is in a pure LP environment like Prolog.
* While I like the use of operator^() to provide cut-like effects, it shouldn't be described as XOR as you're using it. XOR has pretty different semantics. For one, since XOR evaluates to true when its operands are unequal, it can't do short-circuiting any more than the equals relation can.
Guilty as charged. The more natural definition ExOr ^ is not very useful at all in the context of LP. Rather than being pedantic about it... the semantics were slightly modified to short-circuiting which is not the same as the pure definition. It was a usability/readability decision. Since there were only 3 primitive operators to begin with, I felt teaching it wont be an issue. I didn't want to introduce an strange looking operator with a brand new name.
* Can eq_f(), eq_mf() just go away, in favor of using std::bind/tr1::bind instead? You could just provide an overload if eq() that takes a std::function/tr1::function as its second parameter.
That leads to overload resolution issues and also I prefer eq_f separate from eq for clarity of semantics. Though I am thinking of collapsing eq_f and eq_mf into eq_f with some bind mechanism. Boost bind doesn't do the trick as it will not automatically dereference the lrefs involved at the time of evaluation. These were primarily provided to improve readability over the equivalent syntax involving bind.
* What were the limitations that caused you to retain predicate()? I can see how you might still need it in some situations, but most of the time I'd like to use my bool functions/function objects directly instead.
Not sure what you mean. predicate is an adapter relation used to turn bool functions/function objects into relations which can then be combined with other relations. You cannot be use them directly.
Some editorial notes:
Yes thanks very much.

On Tue, May 4, 2010 at 2:58 PM, Roshan <roshan_naik@yahoo.com> wrote:
On Tue, 04 May 2010 10:06:39 -0600, Zach Laine <whatwasthataddress@gmail.com> wrote:
On Thu, Apr 29, 2010 at 2:12 AM, Roshan Naik <roshan_naik@yahoo.com> wrote:
Based on suggestions from some Boost community experts, I would like to gauge interest to see if there is broader interest for including the Castor library into Boost.
This library looks really promising! Â I look forward to using it. Â I have some suggestions about the interface and documentation.
* The semantics of generative queries strike me as wonky. Â I can see the appeal of assigning the result to an uninitialized argument, when there can only be exactly one result returned. Â However, there may be 0, 1, or N. Â That alone lessens the appeal of returning the results in the argument. Â Moreover, you're requiring users to then query the actual result relation to see if it's okay to dereference the lref<> parameter to get at its result.
There is no requirement to inspect the lref. If evaluation of the relation succeeded.. the lref will be initialized.
Right. I understand this bit now.
The idea that a relation can have 0 or more values/solutions is embedded in the theoretical definition relation. It is not a Castor concept. It is fundamental to this paradigm. I will being talking a bit about the concept of a "relation" and how it relates to concept of a "function" in my BoostCon talk. Most other ideas such as "direction-less" or "bi-directional" arguments merely follows from it.
I understand that, and I'm not trying to get you to change the 0 <= N results semantics. I'm just indicating that the canonical way to communicate that in C++ is with a pair of iterators.
Then, you have each call to relation::operator() act as a loop iteration, complete with assignment to the lref<>, and even resetting the lref<> to an uninitialized state.
And now my head hurts. ;)
Since all of this is implicit, someone reading my code, or myself in a year and a half, will probably be left scratching his head.
Having been a traditional programmer, my head hurt too when I encountered this paradigm. Give yourself some time to settle with it.
It's not the N results paradigm. It's the use of a function object and an extrinsic value that gets repeatedly assigned over, instead of a pair of iterators, that hurts my head. Having to use a nonstandard idiom for iteration to get the functionality of your library is what I'm objecting to.
Further, at the call site:
relation franksChildren = father("Frank", c);
How do I know if this is semantically an assertion or a generative query, when I'm reading someone else's code and trying to understand it? Â I have to know a lot more context than I'd like. Â I have to look for all possible places that "c" might come from; whether none, some, or all of them are uninitialized; and which are and which aren't.
It is neither an assertion or a generative query. franksChildren is also a relation (like any other) which can be used to assert or generate. It is merely constraining the first argument to the father relation. You read as "Frank is father of c".
I think you might misunderstand me. I'm pointing out that, as a reader of some code who happens not to be that code's author, I'd like to be able to inspect the code and predict to a reasonable degree what the code does. Knowing whether "while( franksChildren() ) {...}" will *evaluate* to <= 1 result, vs. <= N results, is significant. It is the same semantic difference as find() vs. find_all(). Either might fail to find what it's looking for, but having the two functions instead of just find_all() makes the code more literate. You yourself draw this conceptual distinction between assertion and generative queries in the documentation, no?
Or, in the style of Boost.ForEach or the upcoming standard:
relation franksChildren = father("Frank", any_lref); for (const std::string& child : franksChildren) { Â Â cout << child << " is Frank's child\n"; } cout << "Frank has " << franksChildren.size() << " children";
Good question. There is a fundamental issue with the iterator/enumerator model which makes it unsuitable. The key difference is that in the iterator model divides the following into separate steps: Â 1) "is there more solutions" Â : begin()!=end() Â 2) "get me next solution" : operator ++
There's no fundamental reason why you should be limited by the use of iterators. The iterator constructor invoked for the begin() iterator evaluates the relation once (i.e. it is very much like relation::operator()). If the evaluation succeeded, operator*() will return the result; otherwise, the begin() iterator evaluates as equal to the end() iterator, indicating that the sequence is empty, and that it is unsafe to either dereference or increment the iterator. operator++() simply repeats this process. Am I missing something?
for (const std::string& child : franksChildren) { .. }
wont scale when enumerating with father(f,c) where both f and c are not initialized.
Why is that? relation::operator() works in this case; why can't it work if wrapped in an iterator?
But you could use this syntax if it makes any difference :
for( relation franksChildren = father("Frank", c); franksChildren(); ) { Â ... }
The problem with this is that I not only have to *write* a "c" to catch the results on the stack, but "c" outlives the loop, which is the only place it's actually useful. I prefer to have my loop variable scoped to my loops. In short, we lose the concision of the new for loop syntax, and the scoping of plain old C++ 98 for loops. Anything extra is just noise. In brief, I don't think you should change anything about how relation currently works, including its interaction with lref<>. I just want you to take care of the bookkeeping variables for me, hiding the details behind an iterator interface.
* The way dynamic relations are constructed seems needlessly at odds with the way static relations are contructed. [snip] The motivating issue for Disjunctions/Conjunctions/ExDisjuntions is that this statement is not allowed:
 relation result; // must be initialized
As a relation must be defined. But this is semantically different:
Is there a specific reason for that? Is there a reason why relation()() can't just return false? If so, why not default construct relation the same way, just as Disjunctions initializes its clauses member with False()?
I am toying with this idea of +=.
I'm just trying to keep these relation-implementation types out of users' minds. They don't ever need to know about Disjunctions, Conjunctions, etc., if they can just write |=, &=, etc. It will make the user code more expressive.
* The asymmetry between the use of && and || with ^ is a little bothersome, especially considering the desirability of using &=, |=, and ^= when building relations dynamically. Â Could you use & and | instead of && and ||?
In retrospect, I would like to have used & and | instead of && and ||. But I think its too late now. Â For this case, += can be used for push_back() instead of three different ones.
Why is it too late?
* While I like the use of operator^() to provide cut-like effects, it shouldn't be described as XOR as you're using it. Â XOR has pretty different semantics. For one, since XOR evaluates to true when its operands are unequal, it can't do short-circuiting any more than the equals relation can.
Guilty as charged. The more natural definition ExOr ^ is not very useful at all in the context of LP. Rather than being pedantic about it... the semantics were slightly modified to short-circuiting which is not the same as the pure definition. It was a usability/readability decision. Since there were only 3 primitive operators to begin with, I felt teaching it wont be an issue. I didn't want to introduce an strange looking operator with a brand new name.
Don't get me wrong -- I like the use of operator^(), as I said. Just call it something else. :)
* Can eq_f(), eq_mf() just go away, in favor of using std::bind/tr1::bind instead? Â You could just provide an overload if eq() that takes a std::function/tr1::function as its second parameter.
That leads to overload resolution issues and also I prefer eq_f separate from eq for clarity of semantics. Though I am thinking of collapsing eq_f and eq_mf into eq_f with some bind mechanism. Boost bind doesn't do the trick as it will not automatically dereference the lrefs involved at the time of evaluation. These were primarily provided to improve readability over the equivalent syntax involving bind.
Ah. What was the overload resolution problem?
* What were the limitations that caused you to retain predicate()? Â I can see how you might still need it in some situations, but most of the time I'd like to use my bool functions/function objects directly instead.
Not sure what you mean.
You wrote this in your Design and Implementation doc: "Early on, support for creating relations directly out of a boolean ILE expressions without need for an “adapter” relation like predicate was implemented, but this facility was later withdrawn as it ran into several problems including some limitations imposed by C++. The current design still leaves the door open to revisit this facility in the future (perhaps in C++0x) with an eye towards preserving compatibility."
predicate is an adapter relation used to turn bool functions/function objects into relations which can then be combined with other relations. You cannot be use them directly.
Right. And I'm asking why not. I'm mainly just curious. As an aside, I can write this: lref<int> c; // <- Oops! relation franksChildren = father("Frank", c); and I get this error: includes/refcountedptr.h:98: error: no matching function for call to std::basic_string<char, std::char_traits<char>, std::allocator<char>
::basic_string(const castor::lref<int>&)
It would be nice if it were impossible to mix these due to BOOST_STATIC_ASSERT/static_assert enforcement of type in lref<>, which would provide better feedback. Zach

On Wed, 05 May 2010 09:10:25 -0600, Zach Laine <whatwasthataddress@gmail.com> wrote:
I understand that, and I'm not trying to get you to change the 0 <= N results semantics. I'm just indicating that the canonical way to communicate that in C++ is with a pair of iterators.
Having to use a nonstandard idiom for iteration to get the functionality of your library is what I'm objecting to.
True.. its is canonical to traditional C++ given the existing paradigm mix. Iterators were designed as the "glue" between algorithms/containers/streams. However in LP, all three of them are represented by relations... so iterators are are not that useful. Initially (few years back) I pursued some iterator based designs (among others) which fell apart very quickly. I only recall they didn't fit in very well. All the details escape me now.. But the core idea of being able to dereference an iterator to get a *single* value is at odds with mode of operation here. Coroutines eventually emerged as the more appropriate solution. Introducing iterators based generation of solutions also gives the false impression that this could somehow be used in conjunction with STL's iterator based algorithms... as the *iterator would only produce true/false regardless of the relation. Your interest in iterators seems to be stemming from the desire to use a for each (or range based for loop) like construct to go over all solutions. These are designed to simplify working with iterators... I feel it is more appropriate to extend these looping mechanisms to accomodate coroutines rather than the other way around.
I think you might misunderstand me. I'm pointing out that, as a reader of some code who happens not to be that code's author, I'd like to be able to inspect the code and predict to a reasonable degree what the code does. Knowing whether "while( franksChildren() ) {...}" will *evaluate* to <= 1 result, vs. <= N results, is significant. [..snip..] It is the same semantic difference as find() vs. find_all().
Ah! When you say find().. you are explicitly requesting first result (even if there is more than one) and when you say find_all() you want all results. In LP too it is explicit : First result only (even if there are more): if(franksChildren()) ... All results: while(franksChildren()) ...
There's no fundamental reason why you should be limited by the use of iterators. The iterator constructor invoked for the begin() iterator evaluates the relation once (i.e. it is very much like relation::operator()). If the evaluation succeeded, operator*() will return the result; otherwise, the begin() iterator evaluates as equal to the end() iterator, indicating that the sequence is empty, and that it is unsafe to either dereference or increment the iterator. operator++() simply repeats this process. Am I missing something?
I will need to see a more fleshed out design to comment on this. And see how some of the existing samples in the tutorial would look. This is deeply ingrained decision and not an orthogonal one. BTW how can operator * on the iterator by used to access the multiple in/out parameters ? Too time consuming to list all issues. One of them ... It is likely to imply that when relations are defined imperatively as coroutines, they will be required to define custom iterator objects... which are a huge pain (way too many members!). Also the upcoming lambda support will complement the coroutine style definitions nicely. It is much easier to imperatively define a relation/coroutine using lambda as compared to iterator objects... // psuedocode relation blah(x,y) { return [=] { .. ; yield true; ..; } }
relation result; // must be initialized
As a relation must be defined. But this is semantically different:
Is there a specific reason for that? Is there a reason why relation()() can't just return false? If so, why not default construct relation the same way, just as Disjunctions initializes its clauses member with False()?
Conceptually, the three classes Dis/Con/ExDis-junctions correspond to con/dis/exdis-junctive forms of clause definitions. The type relation has no such association, it is totally free form. The type relation has no such affiliation. So with the three classes, performing += is more naturally suggestive of the implied precedences of the internal operators within the final expression after a series of += (i.e. push_back) operations. I chose not build an implicit semantics at the lowest level concept of type relations. If relation is defaulted to False(). Then realtion&=blah() ... would be False()&&blah(). Which is a problem. But with relation|=blah would be False()||blah() which is not a problem. They could also be just blah(). But it is not distinguishable if relation was default initialized to False or explicitly initialized to False() ... only in the latter case you want to preserve it. I think there were some minor efficiency issues as well... which will take me some effort to recall now. I felt it was not a great idea to build any intelligence into such a low level concept as type relation. That said, i think this still an open case.... just needs to more time to actually experience the trade offs. I think it was good to be conservative decision for an early design stage. It easy to add this into relation .. but removing is near impossible.
Why is it too late?
Compatibility and lack of significant real benefits. The precedence benefits are only if your clauses are in disjunctive normal form. Not otherwise. I have been recently considering having both && and &. Also || and |. As they both are useful in different situations.
Don't get me wrong -- I like the use of operator^(), as I said. Just call it something else. :)
Suggest a better name :) it might happen.
That leads to overload resolution issues and also I prefer eq_f separate from eq for clarity of semantics. Though I am thinking of collapsing eq_f and eq_mf into eq_f with some bind mechanism. Boost bind doesn't do the trick as it will not automatically dereference the lrefs involved at the time of evaluation. These were primarily provided to improve readability over the equivalent syntax involving bind.
Ah. What was the overload resolution problem?
If the obj has a member bool operator()() defined... we cannot say whether eq_f semantics or eq semantics should be applied. It is possible today to apply eq() semantics to objects that have operator().
You wrote this in your Design and Implementation doc:
"Early on, support for creating relations directly out of a boolean ILE expressions without need for an “adapter” relation like predicate was implemented, but this facility was later withdrawn as it ran into several problems including some limitations imposed by C++. The current design still leaves the door open to revisit this facility in the future (perhaps in C++0x) with an eye towards preserving compatibility."
predicate is an adapter relation used to turn bool functions/function objects into relations which can then be combined with other relations. You cannot be use them directly.
Right. And I'm asking why not. I'm mainly just curious.
Oh. An ILE like (i==j) is function obj that returns bool and takes no args. Thus it type erases to relation. But it isn't a relation as it is a subroutine and not a coroutine. No general way to determine if its a truly a relation.
As an aside, I can write this:
lref<int> c; // <- Oops! relation franksChildren = father("Frank", c);
and I get this error:
includes/refcountedptr.h:98: error: no matching function for call to std::basic_string<char, std::char_traits<char>, std::allocator<char>
::basic_string(const castor::lref<int>&)
It would be nice if it were impossible to mix these due to BOOST_STATIC_ASSERT/static_assert enforcement of type in lref<>, which would provide better feedback.
In this case the best place is to probably place the assertion inside father itself. Isn't it ? Boy... I am getting a rigorous mental workout answering all your insightful probing questions. :) -Roshan

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Roshan Naik Sent: Thursday, April 29, 2010 8:12 AM To: boost@lists.boost.org Subject: [boost] [castor] Interest in Logic Paradigm for C++ ?
Based on suggestions from some Boost community experts, I would like to gauge interest to see if there is broader interest for including the Castor library into Boost. In short, Castor's aim is to foster multiparadigm programming in C++ by supporting techniques from the Logic Paradigm. See below for a longer description.
Castor is intended to be a free standing library that depends only on the standard C++ library. It does not depend on Boost or other libraries. It is a pure header library.
A stable 1.0 version has been available since 2008 on www.mpprogramming.com/cpp under the MIT license. Work on version 1.1 is in progress and an early beta is now available. Current efforts are directed largely towards making Castor a richer "standard library" for working with LP in C++.
Castor was not originally targeted for Boost but more recently I have been giving it more serious consideration regarding inclusion into Boost. At the upcoming BoostCon 2010 I will be presenting 'Logic Paradigm for C++'. If there is interest, my thought is that feedback from the Boost review/submission process and modifications to satisfy other Boost requirements/guidelines will perhaps yield a 1.2 version that will become the real Boost candidate. Any help in this space will be much appreciated.
This will be of interest to some - but don't be deterred if the initial response is underwhelming - this is 'niche market' stuff ;-) Many (most?) potential users will not read this group - though you have got a good response from those that do.. I'm fairly ignorant of the 'pro-logicians domain' but it looks in pretty good shape. But a few things I noticed that Boosters generally like for a Boost library are: * use Boost.Test - this is very desirable for the portable testing regime. * included files are .hpp (or .ipp) and * structure of files isn't Boost style (bizarre as it may seem). * ALL files need a licence and copyright. * Quickbook toolchain is preferred documentation method - but you have obviously got a good system going already. pdf are fine but doc not so popular - and not everyone can convert doc to pdf. * Some find Doxygen docs useful for reference - both standalone and as reference section within Quickbook. This ensure that code and docs keep in sync (and save you from (re-)editing the .doc files!). Doxygen reference may be especially useful where the functions of the functions are not as guessable as is common. * the tests provide quite a lot of examples, but a formal libs/example folder with several annotated examples is popular (and is very useful to get people started - as well as the nice tutorial). (Using Quickbook allows you to pick out snippets from header and example files). * using bjam is recommended (though a pig to get going). All these are quite easily fixable (though changing the tests will need some key-bashing). Good luck (and ask here for further help). Paul --- Paul A. Bristow Prizet Farmhouse Kendal, UK LA8 8AB +44 1539 561830, mobile +44 7714330204 pbristow@hetp.u-net.com

On Wed, 05 May 2010 06:05:31 -0600, Paul A. Bristow <pbristow@hetp.u-net.com> wrote:
All these are quite easily fixable (though changing the tests will need some key-bashing).
"Yes" to all of your suggestions. Thanks for listing them out. Not being a Boost-aholic, I have many holes in my knowledge of these Boost essentials. -Roshan

----- Original Message ----- From: "Roshan Naik" <roshan_naik@yahoo.com> To: <boost@lists.boost.org> Sent: Thursday, April 29, 2010 9:12 AM Subject: [boost] [castor] Interest in Logic Paradigm for C++ ?
Based on suggestions from some Boost community experts, I would like to gauge interest to see if there is broader interest for including the Castor library into Boost. In short, Castor's aim is to foster multiparadigm programming in C++ by supporting techniques from the Logic Paradigm.
Hi, I'm interesteed,and as others I have some comments I want to share. * Separation between relation structure and bindings Given // c is child of p relation child(lref<string> c, lref <string> p) { return eq(c,"Sam") && eq(p,"Mary") //fact 1 || eq(c,"Denise") && eq(p,"Mary") //fact 2 || eq(c,"Sam") && eq(p,"Frank")//fact 3 || eq(c,"Denise") && eq(p,"Frank")//fact 4 || eq(c,"Frank") && eq(p,"Gary") //fact 5 ; } The following code lref<string> m,d; relation xx= child(,"Sam", m) && child(,d, ,"Mary") 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. I don't know how this can be done in your library, but in my opinion, the relation structure and the binding should be separated, so the relation structure is shared between all the bindings. * Relation structure definition A relation schema could be strongly typed. Note that I have removed the lref<>, as it seems redundant relation_schema<string,string> father = gender(_1,"male")&& child(_2,_1); _1, _2 are placeholders to name the first and second argumentes of the relation relation_schema<X,Y> defines the operator()(lref(X),lref(Y)) which returns a relation which will bind the arguments. 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"); * Bindings Concrete instances of relation could be constructed by using the operator() as before, but this time it is applied to a relarion_schema. lref<string> c; relation franksChildren = father("Frank", c); while( franksChildren() ) { cout << *c << " is Frank's child\n"; } Note that the code has not been changed. * 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. * 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? Do you think that something like that could be possible with your library. What will be the needed adaptations? Best, Vicente _____________________ Vicente Juan Botet Escribá http://viboes.blogspot.com/

On Wed, 05 May 2010 12:57:07 -0600, vicente.botet <vicente.botet@wanadoo.fr> 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.
* 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". 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. 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;
* 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.
* 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.
* 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. BTW: remember in your code above ... unification is not merely assignment. No need for inheritance either. It would roughly look as follows: struct gender_dyn : Coroutine { list<pair<string,string> > list_; list<pair<string,string> >::iterator current_; gender_dyn(lref<string> p, lref<string> g); bool operator() (void) { co_begin(); list_ = loadData(); for (current_= list_.begin(); current!=list.end(); ++current_ ) { .. unify .. if(unify succeeds) co_yield(true); } if(p was modified) p.reset(); if(g was modified) g.reset(); co_end(); } }; - Roshan

Hi, ----- Original Message ----- From: "Roshan" <roshan_naik@yahoo.com> To: <boost@lists.boost.org> 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@wanadoo.fr> 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/

On Fri, 07 May 2010 08:10:49 -0600, vicente.botet <vicente.botet@wanadoo.fr> wrote:
Is the efficient alternative based on co-routines?
Yes, thats definitely one way.
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?
It is not closed by default since it has to be modifiable at runtime. But you can close it easily if you don't want others to mess with it as show here. Instead of : Disjunctions foo; foo+= ..; You would write: relation foo(..) { Disjunctions res; res+= ...; res+= ...; return res; } Now only foo's author has the ability to mess with it. The default way of doing business with Castor is to keep things closed.
Definitely I need to read completly the documentation. Do you have some tutorials on which we see how this integration is achieved?
Here is a simple one involving polymorphic member relations: template<class T> struct Collection { // interface virtual relation item(lref<T> i) = 0; } template<class T> struct BinaryTree: Collection<T> { virtual relation item(lref<T> i); }; It is easy to visualize how member relations can also be templatized like regular member functions. You can obviously use patterns like CRTP or any other involving inheritance and/or generics. Too many to mention... but I hope you get the idea. You are able to carry those designs naturally forward.
I like this. Is iterable part of the library or an alternative design?
Not yet part of Castor. At the moment its just a thought in my head. If you write one let me know, we could add it in.
Can you point me to the different implementation that is efficient?
The imperative implementation that we just discussed is likely be more efficient in this case. There will be many ways of doing things depending on what relations you already have handy.
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?
Its briefly mentioned in the tutorial under section on "type relation". It is similar to function<bool(void)>. Other than it will take only function objects (not ordinary functions) Reference manual and design doc also have it.
Wow, are coroutines part of the library also? or is just an alternatives design? Could you point to a complete example on the documentation?
They are part of the current 1.1 pre-beta (but not 1.0). Look under section 3 in the tutorial. Also documented in the reference manual.
If all the utilities you have given are already on the library it is time I read completly the documentation.
:-) -Roshan

On 04/29/10 02:12, Roshan Naik wrote: [snip]
================== Links for Castor - v1.1 beta (ported to Gcc 4.4.1 and VC++ 2008) : ==================
Library+docs: http://mpprogramming.com/downloads/prebeta-1.1.zip
[snip] Hi Roshan. I downloaded the .zip file and followed the instructions in the README.txt which contained: GCC (on Unix) -------------------------------------- To compile: g++ -I../ test_castor.cpp -o test_castor To Run : ./test_castor However, apparently several more files need to be compiled and linked because I'm getting the following with that attached Makefile: make -Wtest_castor.cpp /home/evansl/download/gcc/4.5-20100408/install/bin/g++ -c -I/home/evansl/prog_dev/castor/castor_1.1_pre_beta/test/.. -DCASTOR_DISABLE_AND_OPTIMIZATION test_castor.cpp /home/evansl/download/gcc/4.5-20100408/install/bin/g++ test_castor.o -o test_castor.x test_castor.o: In function `runtests()': test_castor.cpp:(.text+0x6557): undefined reference to `test_lref()' test_castor.cpp:(.text+0x6561): undefined reference to `test_begin_end()' test_castor.cpp:(.text+0x656b): undefined reference to `test_or_and()' test_castor.cpp:(.text+0x665b): undefined reference to `test_Prefix_UnaryOps_ILE()' test_castor.cpp:(.text+0x6665): undefined reference to `test_Postfix_UnaryOps_ILE()' test_castor.cpp:(.text+0x666f): undefined reference to `test_eq()' test_castor.cpp:(.text+0x6679): undefined reference to `test_eq_values()' So, shouldn't the README.txt be corrected. TIA. -Larry MAIN=test_castor DOWNLOADGCC.dir=/home/evansl/download/gcc VARISNAP.gcc4_5.dir=$(DOWNLOADGCC.dir)/4.5-20100408 COMPILER.gcc4_5=$(VARISNAP.gcc4_5.dir)/install/bin/g++ COMPILER=$(COMPILER.gcc4_5) COMPILE.opts=-DCASTOR_DISABLE_AND_OPTIMIZATION INCS:= -I$(PWD)/.. $(MAIN).x : $(MAIN).o $(COMPILER) $< -o $@ %.o : %.cpp $(COMPILER) -c $(INCS) $(COMPILE.opts) $*.cpp :PHONY. show_mac show_mac: @echo $(COMPILE.opts)

On 05/19/10 18:39, Larry Evans wrote: [snip]
However, apparently several more files need to be compiled and linked because I'm getting the following with that attached Makefile:
make -Wtest_castor.cpp /home/evansl/download/gcc/4.5-20100408/install/bin/g++ -c -I/home/evansl/prog_dev/castor/castor_1.1_pre_beta/test/.. -DCASTOR_DISABLE_AND_OPTIMIZATION test_castor.cpp /home/evansl/download/gcc/4.5-20100408/install/bin/g++ test_castor.o -o test_castor.x test_castor.o: In function `runtests()': test_castor.cpp:(.text+0x6557): undefined reference to `test_lref()' test_castor.cpp:(.text+0x6561): undefined reference to `test_begin_end()' [snip] The brute force method (compile all test_*.cpp files) in attached gnu Makefile succeeds with output:
g++ test_castor.o test_collection.o test_core.o test_eq.o test_higher_order.o test_ile.o test_io.o test_predicate.o test_tlr.o test_utils.o -o test_castor.x ./test_castor.x Relation myFastAndTestRel copy constructed too many times Failed: 1 Passed: 108 Total: 109 Time taken 20000 Testing Complete! MAIN=test_castor test_castor.deps.cpp=$(wildcard test_*.cpp) test_castor.deps.fn=$(basename $(test_castor.deps.cpp)) OBJECTS=$(addsuffix .o,$($(MAIN).deps.fn)) COMPILER=g++ COMPILE.opts=-DCASTOR_DISABLE_AND_OPTIMIZATION INCS:= -I$(PWD)/.. :PHONY. show_mac run clean run: $(MAIN).x ./$(MAIN).x $(MAIN).x : $(OBJECTS) $(COMPILER) $(OBJECTS) -o $@ %.o : %.cpp $(COMPILER) -c $(INCS) $(COMPILE.opts) $*.cpp show_mac: @echo $(COMPILE.opts) clean: rm $(OBJECTS)

On Wed, 19 May 2010 17:11:17 -0700, Larry Evans <cppljevans@suddenlink.net> wrote:
[snip] The brute force method (compile all test_*.cpp files) in attached gnu Makefile succeeds with output: g++ test_castor.o test_collection.o test_core.o test_eq.o test_higher_order.o test_ile.o test_io.o test_predicate.o test_tlr.o test_utils.o -o test_castor.x ./test_castor.x Relation myFastAndTestRel copy constructed too many times
Hi Larry, Sorry for the late response. Yes, the README.txt should be fixed as you mentioned to compile all test_*.cpp files. Please ignore the one test failure. Seems like that particular failing test case accidentally made it into that pre-beta as it relates to some work-in-progress. thanks for pointing these out. - Roshan
participants (16)
-
Andrew Sutton
-
Barend Gehrels
-
Christoph Heindl
-
Johannes Brunen
-
Larry Evans
-
Oliver Kullmann
-
OvermindDL1
-
Paul A. Bristow
-
Pierre Morcello
-
Robert Jones
-
Robert Ramey
-
Roshan
-
Roshan Naik
-
Vicente Botet Escriba
-
vicente.botet
-
Zach Laine