Thread overview
Function Composition
Jan 24
atzensepp
Jan 24
atzensepp
Jan 24
user1234
Jan 24
user1234
Jan 25
atzensepp
Jan 25
atzensepp
Jan 31
atzensepp
January 24
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)

// 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));
    }
    ~
    ~
    ~

January 24

Some progress: compose function needs to know type but templates help to create for different types.

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:

        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!

January 24

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 ?

January 24

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.

January 25

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.

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);

January 25

On Thursday, 25 January 2024 at 08:25:02 UTC, atzensepp wrote:

>
  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);
January 25

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:

>
  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:

  int delegate (int) td = (x) => compose!(f,g,g,f,g,g,f,g,g,f)(x);

January 29

On Thursday, 25 January 2024 at 18:44:26 UTC, atzensepp wrote:

>

However this works:

  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.

alias td = compose!(f,g);
January 31

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:

  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.

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.