www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Function Composition

reply atzensepp <webwicht web.de> writes:
     How is it possible to compose functions?
     I came up with following solution that is not satisfactory 
for two reasons:
     1. the compose function should be argument agnostic
        here it is explicitly coded for (int) -> (int)
     2. the composition itself requires additional lambda 
expressions
        I would like to write compose(f,g)

```dimport std.stdio;

// Function composition:

int f(int x) { return x*2;} ;
int g(int x) { return x+2;} ;

     int delegate (int) compose( int delegate(int)second, int 
delegate(int)first)
     {
             return ((int i) => second(first(i)));
     }

     void main()
     {
              writeln( compose((x) => f(x),(x) => g(x))(2));
              writeln( compose((x) => g(x),(x) => f(x))(2));
     }
     ~
     ~
     ~

```
Jan 24
parent reply atzensepp <webwicht web.de> writes:
Some progress: compose function needs to know type but templates 
help to create for different types.


```d
import std.stdio;
import std.container.array;

// Function composition:

int f(int x) { return x*2;} ;
int g(int x) { return x+2;} ;

double ff(double x) { return x*x;} ;
double gg(double x) { return 2+x;} ;

template Delegate(T)
{
   T delegate(T) compose( T function(T)second, T function(T )first)
   {
         return ((T i) => second(first(i)));
   }
}

void main()
{
          alias c = Delegate!(int);

          writeln( c.compose(&f,&g)(2));
          writeln( c.compose(&g,&f)(2));

          alias d = Delegate!(double);
          writeln( d.compose(&ff,&gg)(2));
          writeln( d.compose(&gg,&ff)(2));
}

```

Compose function gets 2 pointers to functions and yield a 
delegate.
The created  delegate can be invoked. However it cannot be passed 
to the composition function. This:
```d
         int delegate (int) fg = c.compose(&f,&g);
          int delegate (int) fgf = c.compose(fg,&f);

          writeln( fgf(2));

```
leads to:
```
lambda2.d:41:37: error: function lambda2.Delegate!int.compose 
(int function(int) second, int function(int) first) is not 
callable using argument types (int delegate(int), int 
function(int x))
    int delegate (int) fgf = c.compose(fg,&f);

```

what a bummer!
Jan 24
parent reply user1234 <user1234 12.de> writes:
On Wednesday, 24 January 2024 at 21:12:20 UTC, atzensepp wrote:
 [...]
 what a bummer!
Have you tried https://dlang.org/phobos/std_functional.html#compose ?
Jan 24
parent reply user1234 <user1234 12.de> writes:
On Wednesday, 24 January 2024 at 21:30:23 UTC, user1234 wrote:
 On Wednesday, 24 January 2024 at 21:12:20 UTC, atzensepp wrote:
 [...]
 what a bummer!
Have you tried https://dlang.org/phobos/std_functional.html#compose ?
Well this violates the second requirement:
 the composition itself requires additional lambda expressions
   I would like to write compose(f,g)
I just realize, as this requires template specialization with `!`. But this is how D works with these kind of things.
Jan 24
parent reply atzensepp <webwicht web.de> writes:
On Wednesday, 24 January 2024 at 21:34:26 UTC, user1234 wrote:
 On Wednesday, 24 January 2024 at 21:30:23 UTC, user1234 wrote:
 On Wednesday, 24 January 2024 at 21:12:20 UTC, atzensepp wrote:
 [...]
 what a bummer!
Have you tried https://dlang.org/phobos/std_functional.html#compose ?
Well this violates the second requirement:
 the composition itself requires additional lambda expressions
   I would like to write compose(f,g)
I just realize, as this requires template specialization with `!`. But this is how D works with these kind of things.
Hello, thank you for pointing me to compose! I think i can live with intermediate lambda expression as it is hidden in the template. Obviously functions and delegates are different kinds. And compose from std.functional is excellent as it has varargs and is also very generic. The only rest issue is that I do not know how to get a pointer to composed function. ```d int main() { writeln(compose!(map!(to!(int)), split)("1 2 3").equal([1, 2, 3])); writeln( compose!(f,g,g,f,g,g,f,g,g,f)(8)); int function(int) t = compose!(f,g,g,f,g,g,f,g,g,f); writeln(t(3)); // auto cf = curry!f; // auto cf1 = cf(1); // auto cf2 = cf(2); return(0); } ``` This leads to: ``` gdc lambda4.d lambda4.d:28:25: error: template compose(E)(E a) has no value int function(int) t = compose!(f,g,g,f,g,g,f,g,g,f); ```
Jan 25
parent reply Paul Backus <snarwin gmail.com> writes:
On Thursday, 25 January 2024 at 08:25:02 UTC, atzensepp wrote:
 ```d
   int function(int) t = compose!(f,g,g,f,g,g,f,g,g,f);
 ```

 This leads to:
 ```
 gdc lambda4.d
 lambda4.d:28:25: error: template compose(E)(E a) has no value
    int function(int) t = compose!(f,g,g,f,g,g,f,g,g,f);

 ```
Try using the address operator: // Here // ▼ int function(int) t = &compose!(f,g,g,f,g,g,f,g,g,f);
Jan 25
parent reply atzensepp <webwicht web.de> writes:
On Thursday, 25 January 2024 at 12:19:47 UTC, Paul Backus wrote:
 On Thursday, 25 January 2024 at 08:25:02 UTC, atzensepp wrote:
 ```d
   int function(int) t = compose!(f,g,g,f,g,g,f,g,g,f);
 ```

 This leads to:
 ```
 gdc lambda4.d
 lambda4.d:28:25: error: template compose(E)(E a) has no value
    int function(int) t = compose!(f,g,g,f,g,g,f,g,g,f);

 ```
Try using the address operator: // Here // ▼ int function(int) t = &compose!(f,g,g,f,g,g,f,g,g,f);
Hello, thanks for the hint. But in my environment I am getting the same error: ``` gdc lambda4.d lambda4.d:29:26: error: compose(E)(E a) is not an lvalue int function(int) t = &compose!(f,g,g,f,g,g,f,g,g,f); ``` However this works: ```d int delegate (int) td = (x) => compose!(f,g,g,f,g,g,f,g,g,f)(x); ```
Jan 25
parent reply Inkrementator <anon anon.org> writes:
On Thursday, 25 January 2024 at 18:44:26 UTC, atzensepp wrote:
 However this works:
 ```d
   int delegate (int) td = (x) => 
 compose!(f,g,g,f,g,g,f,g,g,f)(x);

 ```
While not a real function pointer, this might already fit your needs. ```d alias td = compose!(f,g); ```
Jan 29
parent atzensepp <webwicht web.de> writes:
On Monday, 29 January 2024 at 19:24:51 UTC, Inkrementator wrote:
 On Thursday, 25 January 2024 at 18:44:26 UTC, atzensepp wrote:
 However this works:
 ```d
   int delegate (int) td = (x) => 
 compose!(f,g,g,f,g,g,f,g,g,f)(x);

 ```
While not a real function pointer, this might already fit your needs. ```d alias td = compose!(f,g); ```
Dear Inkrementator, thank you very much for this recommendation! This is an effective way to make functions and delegates compatible.
Jan 31