[Boost.Bind] and [Boost.Lambda] problem with partial application and curry

I've been working on implementing some functional idioms in C++ in order to help me learn the Boost.Bind, Boost.Lambda and Boost.Function libraries. I have this (which uses Boost.Bind) #include <boost/function.hpp> #include <boost/bind.hpp> #include <boost/bind/placeholders.hpp> #include <cmath> #include <iostream> template< typename R, typename V1, typename V2 > boost::function< R ( V2 ) > papply( boost::function< R ( V1, V2 ) > f, V1 v ) { return boost::bind( f, v, _1 ); } template< typename R, typename V1, typename V2 > boost::function< boost::function< R ( V1 ) > ( V2 ) > curry( boost::function< R ( V1, V2 ) > f ) { return boost::bind( papply< R, V1, V2 >, f, _1 ); } int add( int a, int b ) { return a + b; } int main() { boost::function< int ( int, int ) > fadd( add ); boost::function< boost::function< int ( int ) > ( boost::function< int ( int, int ) >, int ) > fpapply( papply< int, int, int > ); boost::function< int ( int ) > inc1( papply( fadd, 1 ) ); std::cout << inc1( 6 ) << " " << inc1( 10 ) << std::endl; boost::function< int ( int ) > inc2( fpapply( fadd, 1 ) ); std::cout << inc2( 6 ) << " " << inc2( 10 ) << std::endl; boost::function< boost::function< int ( int ) > ( int ) > curried_add( curry( fadd ) ); boost::function< int ( int ) > inc3( curried_add( 1 ) ); std::cout << inc3( 6 ) << " " << inc3( 10 ) << std::endl; //curry( fpapply ); } Compiling this on MSVC 8.1 SP1 from Boost 1.34.0 RC. I get a nearly 130-line error message, the last part of which is this: 1>e:\dev\boost\install\basic\include\boost-1_34\boost\bind.hpp(278) : error C2664: 'boost::function<Signature> (boost::function<boost::function<int (int)> (boost::function<int (int,int)>,int)>,V1)' : cannot convert parameter 1 from 'int' to 'boost::function<Signature>' 1> with 1> [ 1> Signature=boost::function<int (int)> (int), 1> V1=boost::function<int (int,int)> 1> ] 1> and 1> [ 1> Signature=boost::function<int (int)> (boost::function<int (int,int)>,int) 1> ] 1> No constructor could take the source type, or constructor overload resolution was ambiguous On my web site is the same program (at least the same papply and curry functions), but using Boost.Lambda (there's also a bit of an explanation about what they do). http://www.kirit.com/Blog:/2007-09-10/What%20do%20you%20get%20when%20you%20c... The Boost.Lambda error is even longer at nearly 200 lines. As both libraries give errors I'm inclined to think that I've done something stupid, but both papply() and curry() appear to work. Have I hit a limit on what these two libraries can do, or was there a fix for this between the 1.34.0 RC and 1.34.1 versions? K

Kirit Sælensminde:
template< typename R, typename V1, typename V2 > boost::function< boost::function< R ( V1 ) > ( V2 ) > curry( boost::function< R ( V1, V2 ) > f ) { return boost::bind( papply< R, V1, V2 >, f, _1 ); }
...
boost::function< boost::function< int ( int ) > ( boost::function< int ( int, int ) >, int ) > fpapply( papply< int, int, int > );
...
//curry( fpapply );
Terrific. It seems that fpapply is of the form function<R(V1)>(V2,V3), and curry wants function<R(V1)>(V2).

Peter Dimov wrote:
Kirit Sælensminde:
template< typename R, typename V1, typename V2 > boost::function< boost::function< R ( V1 ) > ( V2 ) > curry( boost::function< R ( V1, V2 ) > f ) { return boost::bind( papply< R, V1, V2 >, f, _1 ); }
...
boost::function< boost::function< int ( int ) > ( boost::function< int ( int, int ) >, int ) > fpapply( papply< int, int, int > );
...
//curry( fpapply );
Terrific.
As in inducing terror? :)
It seems that fpapply is of the form function<R(V1)>(V2,V3), and curry wants function<R(V1)>(V2).
The argument to curry is a binary function of this form: boost::function< R ( V1, V2 ) > fpapply is of this type: boost::function< boost::function< int ( int ) > ( // curry's R boost::function< int( int, int ) >, // curry's V1 int ) > // curry's V2 papply itself is this: boost::function< R ( V2 ) > papply( // curry's R boost::function< R ( V1, V2 ) > f, // curry's V1 V1 v ) // curry's V2 These are in the same form, it's just that V1 is now a function rather than a value. To me it looks like I should be able to pass this in as the binary function to curry. K

Kirit Sælensminde wrote:
http://www.kirit.com/Blog:/2007-09-10/What%20do%20you%20get%20when%20you%20c...
FWIW, Boost.Lambda can curry on the fly. // \x -> (\y -> add(x, y)) bind( __bind__, &add, _1, protect(_1) ) __bind__ is an "imaginary" function object which represents bind itself. If interested in implementation, See: lambda_bind @ http://tinyurl.com/2ekf9q Regards, -- Shunsuke Sogame

shunsuke wrote:
Kirit Sælensminde wrote:
http://www.kirit.com/Blog:/2007-09-10/What%20do%20you%20get%20when%20you%20c...
FWIW, Boost.Lambda can curry on the fly.
// \x -> (\y -> add(x, y)) bind( __bind__, &add, _1, protect(_1) )
__bind__ is an "imaginary" function object which represents bind itself.
If interested in implementation, See: lambda_bind @ http://tinyurl.com/2ekf9q
That's really neat. It looks like you've already done in Egg a lot of the stuff I was going to start going through as well, for example, during the last week I'd been thinking about what you have as fuse and unfuse. I'd also been thinking about generic lazy and memoize higher order functions. What is the status of Egg? K
participants (3)
-
Kirit Sælensminde
-
Peter Dimov
-
shunsuke