
Hi, It was quite difficult to review this submission for several reasons: mostly because (from POV) it has virtually no documentation, no structure, no testing and what is most important no clear defined problem domain, where this library provide a solution (here I mean not the function objects facilities, but namely FP part of the submission). What it does have, is a several interesting ideas. In summary it my opinion this submission is unacceptable and my vote is NO. Problem domain ------------------------------------------------------------------------- Unlike my usual review I would like to start with problem domain discussion. Library position itself as a library to do FP in C++. Namely in this order. Kind of like library for crazy Haskell programmer that for whatever reason decided to use C++. Docs (and papers) in details describe how to do things one could do in Haskell using FPC++ analogs. There is even comparison of performance with Haskell compilers: not to worry we almost as fast. For me as a C++ programmer more important is to see the comparison with the same algorithm implemented with other usual C++ techniques. I did one myself. I took an example used by authors for performance testing and modified it like this: .... here is what is already in test //////////////////////////////////////////////// inline bool is_prime( int i ) { for( int c = 2; c <= i/2; ++c ) { if( i % c == 0 ) return false; } return true; } inline int nth_prime( int N ) { int i = 1; while( N > 0 ) { i++; if( is_prime( i ) ) N--; } return i; } int main() { acc_timer timer; // acc_timer is my timer class based on gettimeoftheday int NUM; cout << "Num primes = "; cin >> NUM; timer.start(); list<int> l = primes(NUM); int i = at( l, NUM-1 ); timer.stop(); cout << i << endl << "took " << timer.elapsed() << " sec" << endl; timer.start(); i = nth_prime( NUM ); timer.stop(); cout << i << endl << "took " << timer.elapsed() << " sec" << endl; } The algorithm I am using similar to the one use by original code. The only difference is that I am not using FC++ abstraction. I was using gcc 3.3.1 under cygwin on my Athlon 2000+ PC. I was using following command for compilation: g++ -O4 -I [list of include directories] tw_primes.cpp Here is the result of several runs: Num primes = 500 3571 took 4.825 sec 3571 took 0.015 sec Num primes = 750 5693 took 11.703 sec 5693 took 0.036 sec In average FC++ solution is 320 times slower. For any practical usage price of an abstraction should not exceed 10-20%. With price as high as FC++ currently shows I wouldn't even start to think in this direction. In general from my experience usage of lazy evaluation quite limited (in FP sense - I do not mean binding the arguments, which is widespread). It may be used sometimes, but I know many more other neat tricks that are more or as useful. IMO authors need to justify need in lazy list as a generic reusable components in C++ (namely in C++ not for FP which says nothing to me), but for now I do not see a place for them. Some papers does try to justify need for FP to implement common design patters in C++. But actually they only shows need for use of polymorphic functors nothing more. Design ------------------------------------------------------------------------- I with almost everything authors says about need of polymorphic functors and the way they design support for result type deduction. But I believe it should be boost-wide solution. With support in both boost::function, boost::bind and boost::lambda. I don't think we need indirect functoids (with their virtual functions and smart_pointers inside). boost::function should be made result_of aware instead. I couldn't comment on design of lazy lists since it does not described in docs. But I still not convinced that there exist a problem to justify need for this construct. Lambda facilities design is also offsite and it's difficult to comment on it by itself and on comparison with boost::lambda. In my personal opinion there should not be two different facilities dedicated to the same cause within boost. If you have any issues with boost::lambda lets resolve them. In other case it would only source of confusion to the users and make them both less useful. Monads are not covered and not commented accordingly. Explicit built-in currying (I prefer term binding) looks like convenient idea and I would vote to include this info boost::function Implicit built-in currying on the other hand like more like a source of confusion than convenience and in my opinion should not be included. It not only may confuse inexperienced user, but also may cause a conflict If I have function polymorphic not only in regards to the type of the arguments but also in regards to their number. I do not understand need for separate notion of thunks. Why couldn't we just bind all function arguments using usual means? Library supply the collection of predefined function object. While I can blindly accept polymorphic counterparts to the STL functional ones, the rest should be documented and discussed one by one (the fact they belong to mythical "prelude" says nothing to me). Also from sources it looks like many of them operate on lazy lists. Why couldn't we have them as a member functions? They are not generic to be used for different kinds of lists (like STL list) and what is an advantage to length ( ll ) vs. ll.length(). Would I need to pass this method anywhere (rare case IMO) I could use an adaptor. Infix syntax: I do not think this feature useful enough to justify weird syntax. Most probably it wouldn't be use for anything other then several functors like plus, minus. Documentation ------------------------------------------------------------------------- There two major problems I have with docs: first they are very scarce on design of the component described and second they are written for Haskell programmer who is learning C++. I believe that at least 90% of C++ practitioners never heard about Haskell. Accordingly it should not be mention in docs AT ALL. The should not be ANY references to Haskell syntax, which instead of clarifying things make it worse and left me with feeling that I did not get something. There should be a short introduction to what is a functional programming paradigm. Comparison with existent C++ paradigms, advantages and disadvantages. I don't say it should be extensive multipage work, but just an introduction for C++ programmer not familiar with FP. There should be reference documentation for any functor supplied by the library. I am not sure there is a need for old (pre boost) references in docs. It absolutely unnecessary for new users. Why existent users may use some kind of transition guide in FC++ website. The rest of docs looks in most part as a "simple overview", while I expect to see a real full documentation. Implementation ------------------------------------------------------------------------- 0. It would be much easier if you would follow recommended boost directory structure 1. BOOST_FCPP_DEFER_DEFINITIONS This does not look like a good solution. What exactly did you try to achieve? 2. definition.cpp What is this? Does it gets compiled by any compiler? 3. All implementations needs to be rewritten using Boost PP to be extendable to more then 3 arguments. 4. Why fullN does not inherit from it's parameter, but keep it as a member instead? 5 What is konst vs. const? 6. When you will eliminate implicit currying implementation became more simple 7. binderNandK...ofM facility does not look extendable. Did you look how boost::bind is implemented? 8. There are still a lot of identifiers that does not follow recommended boost naming policy 9. Why infix syntax implementation is mixed with some library supplied functors? Testing/Examples ------------------------------------------------------------------------- There is a lot of staff in fcpp_clients directory. Since there is no test/examples separation and no Jamfiles I couldn't comment in details how it looks. Regards, Gennadiy.

Thanks much for submitting a formal review and for your comments. You clearly spent a bit of time reviewing the library and I appreciate it. A few quick remarks to address a few of your questions... On Sat, Feb 28, 2004 at 02:53:23PM -0500, Gennadiy Rozental wrote:
I do not understand need for separate notion of thunks. Why couldn't we just bind all function arguments using usual means?
The "usual means" are either explicit currying or implicit currying. Given a 3-arg f: f(x) or f(x,_,_) // result is binary func just binds the first arg, and f(x,y) or f(x,y,_) // result is unary func just binds the first two, but clearly we can't say f(x,y,z) // calls f to bind all three, as this is the syntax to call the function now. As a result, the separate thunk3(f,x,y,z) // result is nullary func is used when you want to bind all N arguments and get back a nullary functor (a thunk).
Implementation ------------------------------------------------------------------------- 1. BOOST_FCPP_DEFER_DEFINITIONS This does not look like a good solution. What exactly did you try to achieve? 2. definition.cpp What is this? Does it gets compiled by any compiler?
Joel de Guzman showed me an elegant solution which gets rid of the need for either of these, so they will disappear.
5 What is konst vs. const?
I think section 10.7 of the docs explains what they do: const_ // Turns a value into a thunk // Ex: const_(3) yields a new function "f": f()=3 konst // Turns a value into a constant unary function // Ex: konst(3) yields a new function "f": f(anything)=3 -- -Brian McNamara (lorgon@cc.gatech.edu)

On Sat, Feb 28, 2004 at 02:53:23PM -0500, Gennadiy Rozental wrote:
I do not understand need for separate notion of thunks. Why couldn't we just bind all function arguments using usual means?
The "usual means" are either explicit currying or implicit currying. Given a 3-arg f:
f(x) or f(x,_,_) // result is binary func
just binds the first arg, and
f(x,y) or f(x,y,_) // result is unary func
just binds the first two, but clearly we can't say
f(x,y,z) // calls f
to bind all three, as this is the syntax to call the function now. As a result, the separate
thunk3(f,x,y,z) // result is nullary func
is used when you want to bind all N arguments and get back a nullary functor (a thunk).
IMO there should not be separate notion of thunk. We need built-in currying and external currying using bind facility. That's it. Gennadiy.

Hi, I vote to accept FC++ into boost. I've had the watch fc++ from its early beginnings. I have a more-or-less deeper understanding of the library. It's a fact that FC++, and especially the so called "functional programming" paradigm has influenced my preferred style of coding. Functional programming is gaining acceptance. The C++ community is moving ever so deeper into FP stemming from the "STL-style" paradigm. Spirit is conceptually a collection of parser and semantic actions, both of which are purely const function objects in the FC++ sense. In FP, and in FC++, this set of parsers are called "parser combinators". Coupled with a way to combine (compose) these function objects to form a whole, we have a very important paradigm. This style of programming is not limited to parsing. Indeed, the most powerful strategy for controlling complexity is 1) to have a set of primitive elements [axioms] 2) A means of combination 3) The means of abstraction. FP is just a means to tackle complexity in these terms. We might be confused with high-priest sounding terms such as currying, lambda, monads, closures, continuations, etc. ad nauseaum, but really, those are means to tackle no. 3 above: abstraction-- how to make complex systems act like they are just like any other primitive in order to make still more complex systems. Equally important are 1 and 2. When reviewing a language (yes, FC++ *is* a language, or more particularly, an EDSL--embedded domain specific language; sure Spirit is also an EDSL), I analyze it based on the three points I listed above. Not surprisingly, FC++ passes those three points-- it's based on haskell! The FP paradigm is a cool idea. Let's have more of it. I vote to accept FC++ into boost. It is a mature library from authors with lots of years of experience in the FP field behind them. * What is your evaluation of the design? I think I already answered that above. The concepts of FC++ are that of Haskell, a time-proven FP language. However, the structure of the library itself needs to be improved. I particularly don't like its apparently monolithic structure. I'm not quite convinced about maintianing purity. There have been some intriguing discussion on both sides. I'd like to see more discussion in this area. * What is your evaluation of the implementation? I've seen FC++ grow. The implementation is robust and sound. However, there are lots of room for improvement. As many have noted already, integration with boost is weak. In addition, I notice a lot of commonality with FC++, BLL and Spirit's Phoenix. I fervently hope that Brian will find some time for collaboration with Jaakko and I. Right now, I am in the process of developing Phoenix-2, which hopefully will be the basis of the anticipated LL/Phoenix merger. There are lots of areas where it will be best to have a common implementation (for one, return type deduction comes to mind). * What is your evaluation of the documentation? In a word: poor. However, I'm sure the author(s) are aware of this and I'm sure we'll see better documentaion in the future. Examples speak volumes. I'd like to see more fully commented or annotated client applications and examples from the simple to the complex preferably hooked into the documentation. Tutorials. I'd like to see a tutorial that hand-holds a would be user into the FC++ realm. * What is your evaluation of the potential usefulness of the library? Lazy lists and lazy evaluation, in particular, is a very powerful concept. This facility alone makes FC++ worth it. I note with enthusism the exact-real application. It wouldn't be possible, or at least be very difficult to code this thing without FC++ and its lazy lists. I would like to experiment, hopefully lots of help from Brian, to implement new forms of *smart* ASTs (abstract syntax trees) with Spirit. I intuit that lazy-evaluation and lazy lists are a key to better ASTs in Spirit. A few years ago, I wanted to use FC++ with Spirit. One reason why I didn't use it was because Spirit was then a boost candidate and one requirement, as a boost candidate, is that Spirit can only use std or boost components. Now, I am enthusuatic that FC++'s authors are here. I hope FC++ will be part of boost. * Did you try to use the library? With what compiler? Did you have any problems? FC++ requires a conforming compiler. It was a good decision for Spirit, starting from 1.8.0 will only support conforming compilers. I haven't tried FC++ with a lot of compilers, but, as a requirement, for Spirit to be able to use FC++, is that it can compile on 1) g++ 3.1 and above, 2) VC7.1, 3) Comeau, 4), Intel 8, 5) CW8. Hopefully, the authors will make sure that it does. * How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? I think that's obvious already ;-) * Are you knowledgeable about the problem domain? Yes. And I hope others will give it a shot at FP. It's a really cool paradigm that will surely make our lives, as coders, more productive. What's not so obvious is that STL is heavily FP flavored. Let's have more of FP in C++! And finally, every review should answer this question: * Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion. I vote to accept FC++ into boost. There are concerns, sure. However, I don't see them as show-stoppers and surely, the authors can fix them before incorporating them into the boost code base. Cheers, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman <joel@boost-consulting.com> writes:
Hi,
I vote to accept FC++ into boost.
I've had the watch fc++ from its early beginnings. I have a more-or-less deeper understanding of the library. It's a fact that FC++, and especially the so called "functional programming" paradigm has influenced my preferred style of coding.
Mine too.
Functional programming is gaining acceptance. The C++ community is moving ever so deeper into FP stemming from the "STL-style" paradigm. Spirit is conceptually a collection of parser and semantic actions, both of which are purely const function objects in the FC++ sense. In FP, and in FC++, this set of parsers are called "parser combinators". Coupled with a way to combine (compose) these function objects to form a whole, we have a very important paradigm.
This style of programming is not limited to parsing. Indeed, the most powerful strategy for controlling complexity is 1) to have a set of primitive elements [axioms] 2) A means of combination 3) The means of abstraction. FP is just a means to tackle complexity in these terms. We might be confused with high-priest sounding terms such as currying, lambda, monads, closures, continuations, etc. ad nauseaum, but really, those are means to tackle no. 3 above: abstraction-- how to make complex systems act like they are just like any other primitive
That's "interoperability". Very important.**
in order to make still more complex systems. Equally important are 1
Well, without primitives, where would we sophisticates be? ;-)
and 2.
Sure, you have to have a way to put primitives together into programs.
When reviewing a language (yes, FC++ *is* a language, or more particularly, an EDSL--embedded domain specific language; sure Spirit is also an EDSL), I analyze it based on the three points I listed above.
The problem, as I see it, is that we already have a DSEL (sorry, I've never seen the "Embedded" placed first) for functional programming in Boost.Lambda that's terser, arguably easier to read, and whose idioms fit more closely with other Boost FP systems (bind, mpl), and existing C++ programming paradigms.
Not surprisingly, FC++ passes those three points-- it's based on haskell!
The FP paradigm is a cool idea. Let's have more of it.
Absolutely. I don't want *anyone* to take these comments too seriously, because I have **not** inveseted the thought that a formal review requires. As I see it, FP is a great approach; using it helps me to manage complex systems by keeping data immutable and by giving me a framework through which to view programming problems (like the STL does). FC++ is certainly an interesting study in DSEL design. If we're going to accept another functional programming language, it ought to justify itself in terms of expressivity or applicability to the problems faced by C++ programmers. I don't have a strong opinion on whether FC++ meets those criteria, but I haven't seen the clear evidence to the affirmative that I'd normally expect by this point in a review. -Dave (**) Monads, OTOH, seem to be a means to tackle the complexity that strict purity introduces in systems that would be more natural with mutable data and deterministic execution order. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
Sure, you have to have a way to put primitives together into programs.
When reviewing a language (yes, FC++ *is* a language, or more particularly, an EDSL--embedded domain specific language; sure Spirit is also an EDSL), I analyze it based on the three points I listed above.
The problem, as I see it, is that we already have a DSEL (sorry, I've never seen the "Embedded" placed first) for functional programming in Boost.Lambda that's terser, arguably easier to read, and whose idioms fit more closely with other Boost FP systems (bind, mpl), and existing C++ programming paradigms.
Darn! I always get confused by those acronyms! No wonder I chose "Spirit" instead of an acronym. I always forget them :-o I have to agree though. I prefer the LL-style operator overloading. As I've already pointed out, it's easy to alleviate the problem of immediate evaluation such as: for_each(f, l, cout << "hello, " << _1); by simply prohibiting automatic LHS and RHS conversion such as the above (flag it as a compile error). Instead, ask the user to always use explicit var(x) and val(x) when dealing with lambda expressions: for_each(f, l, var(cout) << val("hello, ") << _1); Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman <joel <at> boost-consulting.com> writes:
When reviewing a language (yes, FC++ *is* a language, or more particularly, an EDSL--embedded domain specific language; sure Spirit is also an EDSL),
<snip>
* What is your evaluation of the documentation?
In a word: poor. However, I'm sure the author(s) are aware of this and I'm sure we'll see better documentaion in the future.
Examples speak volumes. I'd like to see more fully commented or annotated client applications and examples from the simple to the complex preferably hooked into the documentation.
Tutorials. I'd like to see a tutorial that hand-holds a would be user into the FC++ realm.
I would choose the word 'misdirected'. I just had the pleasure to read the spirit user's guide front-to-back on the weekend, and as a C++ programmer with very little knowledge of the field of parsing, I found it to be very attuned to my learning curve. The documentation in FC++ on the other hand is directed more at programmers who understand the functional programming domain, and now want to apply those concepts in C++. Thus, it didn't really help me identify situations where I would benefit from FC++, and therefore didn't hold my interest through the necesary detail learning phase. (Aside: why is FC++ targetted the way it is? Why are Haskell programmers migrating to C++ anyway? Or is this the wrong conclusion to draw?) I don't think that it's tutorials that are required so much, but motivating examples. I think most C++ programmers come to boost from imperative programming, and it's great to find support in boost for alternative ways of doing things. But documentation for those methods must take the viewpoint that they are introducing alternative methods to C++ programmers in order to be effective. All that aside, misdirected documentation will merely consign FC++ to (relative) obscurity - if the functionality and implementation are of the desired quality, those who already understand the paradigm will derive benefit from its acceptance into boost. Matt

On Mon, Mar 01, 2004 at 11:31:32PM +0000, Matthew Vogt wrote: ...
The documentation in FC++ on the other hand is directed more at programmers who understand the functional programming domain, and now want to apply those concepts in C++.
(Aside: why is FC++ targetted the way it is?
The fact that the Boost FC++ documentation is misdirected is merely a reflection of my own failure as a documentation writer: despite good intentions, I failed to have a nose for my audience. A number of constructive criticisms have been offered, and I think I can do a better job next time around. The fact that most of the prior FC++ documentation is directed at FPers is no accident; rather it's a function of research interest that FC++ generated and the publication venues that prior articles have appeared in. (I will spare any more details here, as it's hard to say much more without making gross generalizations about "the theory people" versus "the practice people", etc.) Ideally I would like for FC++ to help bridge the FP and OOP communities, serving both as a way for C++ programmers to have a platform for realizing more "functional" designs, as well as offering FPers a way to experiment with C++ in a way that's familiar to them. Pragmatically, as a Boost library, the former concern should be more of a priority than the latter. -- -Brian McNamara (lorgon@cc.gatech.edu)

On Mar 1, 2004, at 6:23 PM, Brian McNamara wrote:
... Ideally I would like for FC++ to help bridge the FP and OOP communities, serving both as a way for C++ programmers to have a platform for realizing more "functional" designs, as well as offering FPers a way to experiment with C++ in a way that's familiar to them.
I view such a bridge as a worthy addition to Boost.
Pragmatically, as a Boost library, the former concern should be more of a priority than the latter.
Both concerns must be met to make a satisfactory bridge. I have no doubt that FC++ will meet them once you have incorporated the changes discussed in this review. I fully support the acceptance of this library into Boost. Gregory Colvin PhD Java Virtual Machine Group Oracle Corporation gregory.colvin@oracle.com 650-633-6041 (office, voice mail and FAX)

Brian McNamara wrote:
The fact that most of the prior FC++ documentation is directed at FPers is no accident; rather it's a function of research interest that FC++ generated and the publication venues that prior articles have appeared in. (I will spare any more details here, as it's hard to say much more without making gross generalizations about "the theory people" versus "the practice people", etc.)
As much as we'd like to avoid the "academia vs trenches" issue, from time to time it becomes pretty much impossible to ignore, and one of these times is now. FC++, as presented, just looks and feels too much a research project to the ordinary C++ practitioner. It would probably help a lot if its "sales pitch" did take into account the "trenches" viewpoint. Just my opinion.
participants (7)
-
Brian McNamara
-
David Abrahams
-
Gennadiy Rozental
-
Gregory Colvin
-
Joel de Guzman
-
Matthew Vogt
-
Peter Dimov