2

Consider the following method:

int Foo(string st, float x, int j)
{
    ...
}

Now I want to wrap it in a delegate of type Func<float, int> by providing values for the parameters st and j. But I don't know the syntax. Can someone help?

This is the idea (might look a bit Haskell-ish):

Func<float, int> myDelegate = new Func<float, int>(Foo("myString", _ , 42));
// by providing values for st and j, only x is left as a parameter and return value is int
Kjara
  • 2,504
  • 15
  • 42
  • 2
    There is no partial application in C#: all arguments to a function call must be specified. However, a "wrapping function" (that calls the original function) can be created which can emulate such.. – user2864740 Oct 20 '16 at 06:24

4 Answers4

7

This should do the trick:

Func<float, int> f = (x) => { return Foo("myString", x, 42); };

Partially applying functions the way you want to do it is currently only possible in F#, not in C#.

CookedCthulhu
  • 744
  • 5
  • 14
  • Do you know where is the syntactic difference between your line of code (which works for me) and the following? I have a method `void Bar(string st) { ... }` and now somewhere I write `Action a = (x) => { return Bar(x); };`. But here the compiler complains "Delegate 'Action' does not take 1 argument." But there is no argument left! What's wrong with this syntax? It's just the same as above... – Kjara Oct 20 '16 at 06:33
  • Probably because you can't return void and Action also doesn't return anything. – CookedCthulhu Oct 20 '16 at 06:37
  • But `Action a = (x) => Bar(x);` doesn't work either... (still says "Delegate 'Action' does not take 1 argument") – Kjara Oct 20 '16 at 06:38
  • 1
    @Kjara `Action a = (x) => ..` – user2864740 Oct 20 '16 at 06:38
  • I was confused. What I really wanted to do was this (which works): `Action a = () => Bar("myString");`. Thanks! – Kjara Oct 20 '16 at 06:40
4

There's no specific syntax for partial application. You can emulate it by

Func<int, int, int, int> multiply = (a, b, c) => a*b*c;
Func<int, int, int> multiplyPartialApplication = (a, b) => multiply(a, b, 100);

Be aware that this might not be something you want to do in resource-constrained applications, since it will cause extra allocations.

robhol
  • 195
  • 1
  • 11
1

[Necromancy]

I believe this alternative is the most flexible and straightforward although somewhat difficut to get if not used to that exercise.

// Given
int Foo(string st, float x, int j) => default;

// Inlined partial application
Func<string, int, Func<float, int>> applyFoo
    = (st, j) => (x) => Foo(st, x, j);
// Or as part of a function
Func<float, int> ApplyFoo(string st, int j)
    => (x) => Foo(st, x, j);

// Usage
var bar = 42;
var appliedFoo = applyFoo("foo", bar);
var result = appliedFoo(12.34);
// Or
var result = applyFoo("foo", bar)(12.34);

The choice of the argument's order makes a difference in this situation as this would have been simpler to deal with (via a pApply helper) if Foo would have been defined as int Foo(string st, int j, float x) since it is quite easy to create a positional partial application helper.

gfache
  • 606
  • 6
  • 15
0

I hope this solution helps:

    public static class FunctionExtensions
    {
        public static Func<T1, Func<T2, Func<T3, TResult>>> Curried<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> func)
        {
            return x1 => x2 => x3 => func(x1, x2, x3);
        }
    }

    //you create your delegate
    var myDelegate = new Func<string, int, float, int>((st, j, x) => Foo(st, x, j)).Curried();

    //call it with your two specified parameters where you have only them and pass the returned function that expects your float parameter
    var returnedFunction = myDelegate("myString")(42);

    //call the returned function eventually with your float parameter
    var result = returnedFunction(0f);
V. S.
  • 1,086
  • 14
  • 14