www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Higher-order functions?

reply "Jonas H." <jonas lophus.org> writes:
Hi everyone,

does D have any runtime higher-order function facilities? (I'm not 
talking about templates.)

More specifically, is something like this possible? (That's how I'd do 
it in Python)

car_prices = map(Car.get_price, list_of_cars)

car = new Car
foobar(car.get_price)

Thanks
Jonas
Apr 10 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/11/2012 01:13 AM, Jonas H. wrote:
 Hi everyone,

 does D have any runtime higher-order function facilities?

D has full runtime support for higher-order functions and closures. import std.stdio; int[] map(scope int delegate(int) f, int[] a){ auto b = new int[a.length]; foreach(i,x;a) b[i] = f(x); return b; } void main(){ int a = 2; writeln(map(x=>a*x, [1,2,3])); }
 (I'm not  talking about templates.)

You will often use templates together with runtime higher order functions. Eg: import std.stdio; T[] map(T,S)(scope T delegate(S) f, S[] a){ auto b = new T[a.length]; foreach(i,x;a) b[i] = f(x); return b; } void main(){ int a = 2; writeln(map((int x)=>a*x, [1,2,3])); writeln(map((double x)=>a*x, [1.6,2.7,3.8])); } For function literals that contain more than one statement, there is an alternate syntax: auto dg = (int a, double b){a*=b; return a+b;} You can explicitly specify 'function' or 'delegate': auto fp = function (int x) => 2*x; // not a closure, simple function pointer (uses less space, but is less powerful) int a = 2; auto dg = delegate (int x) => a*x; // closure, can refer to a You can leave out argument types when they can be directly deduced from the context. Finally, if the literal has an explicit 'function' or 'delegate' it is possible to explicitly specify the return type: auto dg = delegate int(int x) => x;
 More specifically, is something like this possible? (That's how I'd do
 it in Python)

 car_prices = map(Car.get_price, list_of_cars)

 car = new Car
 foobar(car.get_price)

 Thanks
 Jonas

(Well, the standard way to do what that python code does is using templates. auto car_prices = map!(car => car.get_price)(list_of_cars);// lazy range auto car_prices = array(map!(car => car.get_price(list_of_cars)); // eager array)
Apr 10 2012
next sibling parent "Nick Sabalausky" <SeeWebsiteToContactMe semitwist.com> writes:
"Timon Gehr" <timon.gehr gmx.ch> wrote in message 
news:jm2hnp$s0s$1 digitalmars.com...
 (Well, the standard way to do what that python code does is using 
 templates.

 auto car_prices = map!(car => car.get_price)(list_of_cars);// lazy range
 auto car_prices = array(map!(car => car.get_price(list_of_cars)); // eager 
 array)

And keep in mind, too, even though those high-order functions take the delegate/closure as a template paramater, you CAN still rig it up for the delegate/closure to be changed at runtime (as long as the delegate's signature is the same): auto myDelegate = (Car c) => c.getPrice; // Change it at runtime: if(foo) myDelegate = (Car c) => c.getPrice + 7; auto carPrices = map!myDelegate(list_of_cars);
Apr 10 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-04-11 10:45, Xan wrote:
 Good answer.

 For the other hand, what is the simplest method for implementing this
 (in pseucode) in D:

 Sure:

 FUNC someprocedure(int a, int b, func<int, int: int> f) int
 RETURN f(a, b)
 }

 And call it with:

 IO.writeLine("add: " .. someprocedure(2, 3, { a, b => a + b }))
 IO.writeLine("multiply: " .. someprocedure(2, 3, { a, b => a * b }))

 (Read the => as "gives")

 Is it possible to have this?

If I understand the above code correctly: import std.stdio; int someprocedure (int a, int b, int delegate (int, int) f) { return f(a, b); } void main () { writeln("add: ", someprocedure(2, 3, (a, b) => a + b)); writeln("multiply: ", someprocedure(2, 3, (a, b) => a * b)); } -- /Jacob Carlborg
Apr 11 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/11/2012 11:37 AM, Xan wrote:
 On Wednesday, 11 April 2012 at 09:17:12 UTC, Jacob Carlborg wrote:
 On 2012-04-11 10:45, Xan wrote:
 Good answer.

 For the other hand, what is the simplest method for implementing this
 (in pseucode) in D:

 Sure:

 FUNC someprocedure(int a, int b, func<int, int: int> f) int
 RETURN f(a, b)
 }

 And call it with:

 IO.writeLine("add: " .. someprocedure(2, 3, { a, b => a + b }))
 IO.writeLine("multiply: " .. someprocedure(2, 3, { a, b => a * b }))

 (Read the => as "gives")

 Is it possible to have this?

If I understand the above code correctly: import std.stdio; int someprocedure (int a, int b, int delegate (int, int) f) { return f(a, b); }

Yes, you undertood correcty. Your code gives me an error: $ gdmd-4.6 funcions.d funcions.d:10: expression expected, not '>' funcions.d:10: found 'a' when expecting ',' funcions.d:11: expression expected, not '>' funcions.d:11: found 'a' when expecting ','
 void main ()
 {
     writeln("add: ", someprocedure(2, 3, (a, b) => a + b));
     writeln("multiply: ", someprocedure(2, 3, (a, b) => a * b));
 }


AFAIK GDC does not yet support the new lambda literal syntax. You can use void main () { writeln("add: ", someprocedure(2, 3, (a, b) { return a + b; })); writeln("multiply: ", someprocedure(2, 3, (a, b) { return a * b; })); }
Apr 11 2012
next sibling parent Mirko Pilger <pilger cymotec.de> writes:
 What is the error?

e.g. try this: auto someprocedure (int a, int b, int delegate (int, int) f)
Apr 11 2012
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 04/11/2012 11:51 AM, Xan wrote:
 On Wednesday, 11 April 2012 at 09:43:27 UTC, Timon Gehr wrote:
 On 04/11/2012 11:37 AM, Xan wrote:
 On Wednesday, 11 April 2012 at 09:17:12 UTC, Jacob Carlborg wrote:
 On 2012-04-11 10:45, Xan wrote:
 Good answer.

 For the other hand, what is the simplest method for implementing this
 (in pseucode) in D:

 Sure:

 FUNC someprocedure(int a, int b, func<int, int: int> f) int
 RETURN f(a, b)
 }

 And call it with:

 IO.writeLine("add: " .. someprocedure(2, 3, { a, b => a + b }))
 IO.writeLine("multiply: " .. someprocedure(2, 3, { a, b => a * b }))

 (Read the => as "gives")

 Is it possible to have this?

If I understand the above code correctly: import std.stdio; int someprocedure (int a, int b, int delegate (int, int) f) { return f(a, b); }

Yes, you undertood correcty. Your code gives me an error: $ gdmd-4.6 funcions.d funcions.d:10: expression expected, not '>' funcions.d:10: found 'a' when expecting ',' funcions.d:11: expression expected, not '>' funcions.d:11: found 'a' when expecting ','
 void main ()
 {
    writeln("add: ", someprocedure(2, 3, (a, b) => a + b));
    writeln("multiply: ", someprocedure(2, 3, (a, b) => a * b));
 }


AFAIK GDC does not yet support the new lambda literal syntax. You can use void main () { writeln("add: ", someprocedure(2, 3, (a, b) { return a + b; })); writeln("multiply: ", someprocedure(2, 3, (a, b) { return a * b; })); }

Better but with error ;-) $ gdmd-4.6 func2.d func2.d:10: Error: undefined identifier a func2.d:10: Error: undefined identifier b func2.d:10: Error: function func2.someprocedure (int a, int b, int delegate(int, int) f) is not callable using argument types (int,int,_error_ delegate(_error_, _error_)) func2.d:10: Error: cannot implicitly convert expression (__dgliteral1) of type _error_ delegate(_error_, _error_) to int delegate(int, int) With: import std.stdio; int someprocedure (int a, int b, int delegate (int, int) f) { return f(a, b); } void main () { writeln("add: ", someprocedure(2, 3, (a, b) { return a + b; } )); writeln("multiply: ", someprocedure(2, 3, (a, b) { return a * b; } )); } What is the error?

Apparently your compiler does not support parameter type deduction yet. void main () { writeln("add: ", someprocedure(2, 3, (int a, int b) { return a + b; })); writeln("multiply: ", someprocedure(2, 3, (int a, int b) { return a * b; })); }
Apr 11 2012
prev sibling next sibling parent "Nick Sabalausky" <SeeWebsiteToContactMe semitwist.com> writes:
"Jonas H." <jonas lophus.org> wrote in message 
news:mailman.1600.1334099651.4860.digitalmars-d-learn puremagic.com...
 Hi everyone,

 does D have any runtime higher-order function facilities? (I'm not talking 
 about templates.)

Yes. Fully. Many are already in the std lib: http://dlang.org/phobos/std_algorithm.html
 More specifically, is something like this possible? (That's how I'd do it 
 in Python)

 car_prices = map(Car.get_price, list_of_cars)

Just as one example (These all work as of DMD 2.058): import std.algorithm; // For 'map' class Car {...blah...} int getPrice(Car c) {return ...blah...;} void main() { auto listOfCars = [new Car()]; auto carPrices = listOfCars.map!getPrice(); } Or: import std.algorithm; // For 'map' class Car { ...blah... property int price() {return ...blah...;} } void main() { auto listOfCars = [new Car()]; auto carPrices = listOfCars.map!( (Car c) => (c.price) )(); //or auto getPrice = (Car c) => (c.price); // getPrice can be reassigned at runtime auto carPrices = listOfCars.map!getPrice(); }
 car = new Car
 foobar(car.get_price)

class Car { ...blah... int getPrice() {return ...blah...;} } void foobar(int delegate() dg) { auto x = dg(); } void main() { auto car = new Car(); foobar(&car.getPrice); }
Apr 10 2012
prev sibling next sibling parent "Xan" <xancorreu gmail.com> writes:
Good answer.

For the other hand, what is the simplest method for implementing 
this (in pseucode) in D:

Sure:

FUNC someprocedure(int a, int b, func<int, int: int> f) int
   RETURN f(a, b)
}

And call it with:

   IO.writeLine("add: " .. someprocedure(2, 3, { a, b => a + b }))
   IO.writeLine("multiply: " .. someprocedure(2, 3, { a, b => a * 
b }))

(Read the => as "gives")

Is it possible to have this?

Thanks,
Xan

On Wednesday, 11 April 2012 at 00:03:05 UTC, Timon Gehr wrote:
 On 04/11/2012 01:13 AM, Jonas H. wrote:
 Hi everyone,

 does D have any runtime higher-order function facilities?

D has full runtime support for higher-order functions and closures. import std.stdio; int[] map(scope int delegate(int) f, int[] a){ auto b = new int[a.length]; foreach(i,x;a) b[i] = f(x); return b; } void main(){ int a = 2; writeln(map(x=>a*x, [1,2,3])); }
 (I'm not  talking about templates.)

You will often use templates together with runtime higher order functions. Eg: import std.stdio; T[] map(T,S)(scope T delegate(S) f, S[] a){ auto b = new T[a.length]; foreach(i,x;a) b[i] = f(x); return b; } void main(){ int a = 2; writeln(map((int x)=>a*x, [1,2,3])); writeln(map((double x)=>a*x, [1.6,2.7,3.8])); } For function literals that contain more than one statement, there is an alternate syntax: auto dg = (int a, double b){a*=b; return a+b;} You can explicitly specify 'function' or 'delegate': auto fp = function (int x) => 2*x; // not a closure, simple function pointer (uses less space, but is less powerful) int a = 2; auto dg = delegate (int x) => a*x; // closure, can refer to a You can leave out argument types when they can be directly deduced from the context. Finally, if the literal has an explicit 'function' or 'delegate' it is possible to explicitly specify the return type: auto dg = delegate int(int x) => x;
 More specifically, is something like this possible? (That's 
 how I'd do
 it in Python)

 car_prices = map(Car.get_price, list_of_cars)

 car = new Car
 foobar(car.get_price)

 Thanks
 Jonas

(Well, the standard way to do what that python code does is using templates. auto car_prices = map!(car => car.get_price)(list_of_cars);// lazy range auto car_prices = array(map!(car => car.get_price(list_of_cars)); // eager array)

Apr 11 2012
prev sibling next sibling parent "Xan" <xancorreu gmail.com> writes:
On Wednesday, 11 April 2012 at 09:17:12 UTC, Jacob Carlborg wrote:
 On 2012-04-11 10:45, Xan wrote:
 Good answer.

 For the other hand, what is the simplest method for 
 implementing this
 (in pseucode) in D:

 Sure:

 FUNC someprocedure(int a, int b, func<int, int: int> f) int
 RETURN f(a, b)
 }

 And call it with:

 IO.writeLine("add: " .. someprocedure(2, 3, { a, b => a + b }))
 IO.writeLine("multiply: " .. someprocedure(2, 3, { a, b => a * 
 b }))

 (Read the => as "gives")

 Is it possible to have this?

If I understand the above code correctly: import std.stdio; int someprocedure (int a, int b, int delegate (int, int) f) { return f(a, b); }

Yes, you undertood correcty. Your code gives me an error: $ gdmd-4.6 funcions.d funcions.d:10: expression expected, not '>' funcions.d:10: found 'a' when expecting ',' funcions.d:11: expression expected, not '>' funcions.d:11: found 'a' when expecting ','
 void main ()
 {
     writeln("add: ", someprocedure(2, 3, (a, b) => a + b));
     writeln("multiply: ", someprocedure(2, 3, (a, b) => a * b));
 }

Apr 11 2012
prev sibling next sibling parent "Xan" <xancorreu gmail.com> writes:
On Wednesday, 11 April 2012 at 09:43:27 UTC, Timon Gehr wrote:
 On 04/11/2012 11:37 AM, Xan wrote:
 On Wednesday, 11 April 2012 at 09:17:12 UTC, Jacob Carlborg 
 wrote:
 On 2012-04-11 10:45, Xan wrote:
 Good answer.

 For the other hand, what is the simplest method for 
 implementing this
 (in pseucode) in D:

 Sure:

 FUNC someprocedure(int a, int b, func<int, int: int> f) int
 RETURN f(a, b)
 }

 And call it with:

 IO.writeLine("add: " .. someprocedure(2, 3, { a, b => a + b 
 }))
 IO.writeLine("multiply: " .. someprocedure(2, 3, { a, b => a 
 * b }))

 (Read the => as "gives")

 Is it possible to have this?

If I understand the above code correctly: import std.stdio; int someprocedure (int a, int b, int delegate (int, int) f) { return f(a, b); }

Yes, you undertood correcty. Your code gives me an error: $ gdmd-4.6 funcions.d funcions.d:10: expression expected, not '>' funcions.d:10: found 'a' when expecting ',' funcions.d:11: expression expected, not '>' funcions.d:11: found 'a' when expecting ','
 void main ()
 {
    writeln("add: ", someprocedure(2, 3, (a, b) => a + b));
    writeln("multiply: ", someprocedure(2, 3, (a, b) => a * 
 b));
 }


AFAIK GDC does not yet support the new lambda literal syntax. You can use void main () { writeln("add: ", someprocedure(2, 3, (a, b) { return a + b; })); writeln("multiply: ", someprocedure(2, 3, (a, b) { return a * b; })); }

Better but with error ;-) $ gdmd-4.6 func2.d func2.d:10: Error: undefined identifier a func2.d:10: Error: undefined identifier b func2.d:10: Error: function func2.someprocedure (int a, int b, int delegate(int, int) f) is not callable using argument types (int,int,_error_ delegate(_error_, _error_)) func2.d:10: Error: cannot implicitly convert expression (__dgliteral1) of type _error_ delegate(_error_, _error_) to int delegate(int, int) With: import std.stdio; int someprocedure (int a, int b, int delegate (int, int) f) { return f(a, b); } void main () { writeln("add: ", someprocedure(2, 3, (a, b) { return a + b; } )); writeln("multiply: ", someprocedure(2, 3, (a, b) { return a * b; } )); } What is the error?
Apr 11 2012
prev sibling next sibling parent "Xan" <xancorreu gmail.com> writes:
On Wednesday, 11 April 2012 at 10:14:21 UTC, Mirko Pilger wrote:
 What is the error?

e.g. try this: auto someprocedure (int a, int b, int delegate (int, int) f)

I receive the same error
Apr 11 2012
prev sibling parent "Xan" <xancorreu gmail.com> writes:
 Apparently your compiler does not support parameter type 
 deduction yet.

 void main ()
 {
     writeln("add: ", someprocedure(2, 3, (int a, int b) { 
 return a + b; }));
     writeln("multiply: ", someprocedure(2, 3, (int a, int b) { 
 return a * b; }));
 }

Yes, now it works! Thanks,
Apr 11 2012