
On Tue, Feb 17, 2004 at 08:54:25AM +0900, Darren Cook wrote:
Thanks for the detailed reply Brian.
No problem; thanks for showing an interest in the library! :)
1. (from the paper) int a[]={5,3,8,4}; std::for_each(a,a+4,std::cout<<_1<<"\n");
In FC++ it'd look like this:
std::for_each(a,a+4, lambda(X)[ &cout %out_stream% X %out_stream% '\n' ] );
The use of X is just tradition is it? I could just as easily use _1, or some meaningful variable? Being able to name the variable is an advantage.
Yes; in the (previously) attached example you can see that you may name it whatever you like.
On the other hand %out_stream% is not as nice as <<. Is FC++ overloading operator<< an option? I think the "Hello World" examples have to be as attractive as possible to bring the punters in.
The paper "Syntax sugar for FC++: lambda, infix, monads, and more" discusses a bit of the design rationale here, but here's a capsule summary: - FC++ has "named functoids" for the operators, because these named entities can be used in lots of ways: plus(x,y) f(plus) 3 ^plus^ 4 plus[X,3] plus(1) You can't do all the same things with operators (like "+"). - Overloaded operators do give you better lambda syntax, but sometimes at the cost of surprises, like this example int a[]={5,3,8,4}; std::for_each(a,a+4,std::cout<<"v="<<_1<<"\n"); // whoops, forgot constant(), does wrong thing - We overloaded operators as other kinds of syntax sugar (e.g. ^, %, and [] seen above). Basically "we went a different way". There are some examples that are shorter/simpler/easier/whatever with fcpp::lambda, and there are many examples that are s/s/e/w with boost::lambda. Use the one that works for you. (For the most part, the libraries should interoperate.)
lambda(X)[ &cout %out_stream% string("v=") %out_stream% X %out_stream% '\n' ] );
Same thing here, with the added annoyance that you have to manually turn the string literal into some "by-value" type....
But after reading your source I realized this is doing a different job to constant() in BLL isn't it. It is just the "..." string that is the problem, not that the lambda variable is not the first thing in the expression.
I'm not quite sure I understand your question, but: - In boost::lambda, you sometimes need constant() when the lambda variable isn't the first/deepest thing in the expression. In FC++, this is not an issue (or it is a different kind of issue, depending on how you view things) owing to the use of % and [] in lambda expressions. - In FC++, string literals never seem to work as parameters because the templates always infer their types as "array of const char", and arrays can't be "copied", or some such annoying thing. But string literals are an issue orthogonal to the evaluation order issue.
I was hoping you might have some way to get rid of the "&MyClass::" bit, so I could write: lambda(test)[ test->save(f) ]
Nope. In fact, it's impossible to write a C++ library to let you do that in general (that is, one that works for any member function).
In most of my real code "MyClass" is actually a 60 character monster with template parameters; I usually give in and a write a for() loop for that reason (i.e. it is quicker to type the for() loop out than go hunting through my code to get the exact class name definition).
This is off-topic, but invoke the help of your text editor here. If I have a class named SomethingReallyHorribleAndLong, I don't retype its name all over the place, rather I type "Som^P" and vim (my editor) expands it into "SomethingReallyHorribleAndLong". (This doesn't help make the code less ugly to look at, but it does make it easier to type.)
Note that if "save" were defined by MyClass as a functoid, things get even easier in the client code; see the attached example (and YourClass) for details.
Have you thought of supplying some macros to help - my eyes kept bouncing off the code in YourClass.
No--you almost never do this (what I did in YourClass) anyway. Rather you usually would just choose to make "save" a "global" functoid (this goes along with some general C++ wisdom anyway; see http://www.cuj.com/documents/s=8042/cuj0002meyers/ for example), and thus call save( yc, f ); // or yc ^save^ f rather than yc.save(f); That is the simple solution; the stuff I showed with YourClass just illustrates how it's possible to get "cute" and use functoids with member syntax. Again, it's a matter of what you are going to do with your classes/methods. If you want to use them lots in FC++, making lots of higher-order functions and lambda expressions, then you should write functoids. If not, then just write classes/methods as usual, and be willing to occasionally have to spell out ptr_to_fun(&MyClass::save).
... the gist of it would again be that
bind(&MyClass::on_name, this, _1,_2)
would be spelled
ptr_to_fun(&MyClass::on_name)(this)
Interesting. I cannot decide if I like _1,_2 disappearing or not (I'm trying to think about when I look at it in 6 months time).
If you do lots of functional programming, then you'll grow so accustommed to currying (leaving off trailing arguments) that you won't even think about it. I suppose an FP-er is more likely to write foldl(op) whereas others might prefer foldl(op,_,_) since foldl takes 3 arguments. -- -Brian McNamara (lorgon@cc.gatech.edu)