How To: Passing curried functions around

Ali Çehreli via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Fri Sep 11 11:39:14 PDT 2015


On 09/11/2015 02:41 AM, Bahman Movaqar wrote:
 > On Friday, 11 September 2015 at 06:14:18 UTC, Ali Çehreli wrote:
 >> partial takes the function arguments as 'value template parameters'.
 >> Unfortunately, a function pointer like &isEven cannot be 'value
 >> template parameters'; only fundamental types and strings can... So,
 >> 'partial' is not an option for this problem.
 >
 > Ah...now I understand the mysterious compiler errors.

I was wrong there: 'partial' does take its arguments as alias template 
parameters but it still doesn't work probably because of a compiler or 
language issue:

import std.functional;

alias Validator = bool function(int);

bool condition(int)
{
     return true;
}

void foo(Validator validator)
{
     validator(42);
}

void main()
{
     alias f = partial!(foo, condition);    // <-- ERROR
}

/usr/include/dmd/phobos/std/functional.d(662): Error: function 
deneme.condition (int _param_0) is not callable using argument types ()
/usr/include/dmd/phobos/std/functional.d(662): Error: cannot return 
non-void from void function

I wouldn't expect an actual call for that line of code but the compiler 
thinks that there is a call to condition() without a parameter. (This 
may be related to a syntax issue caused by no-parameter functions being 
called without parentheses.)

 >> Idiomatic D uses templates and passes behavior in the form of 'alias
 >> template parameters.' Alias template parameters are the convenient way
 >> of allowing anything that is callable, not just functions. For
 >> example, foo() would be much more useful if it allowed a delegate or a
 >> class object that has an overloaded opCall() operator.
 >
 > True.  I guess I was just pushing D functions too far.

Not necessarily. You can do the same thing with function pointers as 
well but I don't think 'partial' has much to offer over a lambda. I am 
guessing that partial predates lambdas. (?)

 >>   http://ddili.org/ders/d.en/parallelism.html
 >>
 >> (Search for "The task function above has been specified as a template
 >> parameter" on that page.)
 >
 > Actually, I *am* using your book (which is, by the way, very well
 > written) plus the language specs to learn D.  However, that section yet
 > too advance for me to touch :-)
 >
 >> import std.stdio;
 >>
 >> bool isEven(int n) {
 >>     return !(n % 2);
 >> }
 >>
 >> int readValidInt(alias validator)(string prompt) {

readValidInt() is a function template that takes two information:

1) The validator as its alias template parameter. alias template 
parameter allows it to work with anything that can be called.

2) The prompt as its function parameter.

 >>     while (true) {
 >>         int i;
 >>         write(prompt);
 >>         readf(" %s", &i);
 >>         if (validator(i)) {
 >>             return i;
 >>         } else {
 >>             writeln("Sorry, that's not acceptable");
 >>         }
 >>     }
 >> }

The should be obvious.

 >> void foo(alias reader)() {
 >>     reader();
 >> }

Another function template that takes a callable entity and calls it.

 >> void main() {
 >>     auto reader = () => readValidInt!isEven("Enter an integer: ");

The syntax above creates a lambda with this definition: Call 
readValidInt!isEven with the string argument "Enter an integer: ".

 >>     foo!reader();

foo takes that lambda. When foo eventually calls the lambda, 
readValidInt!isEven("Enter an integer: ") will be called.

 >> }
 >>
 >> You can add template constraints to make the code easier to use.
 >
 > Clean one!  Even though I don't know what's going behind the scenes, I
 > can easily read and understand it.
 >
 > Thanks for the help.

Ali



More information about the Digitalmars-d-learn mailing list