4

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
1
  • 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.. Commented Oct 20, 2016 at 6:24

4 Answers 4

8

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#.

Sign up to request clarification or add additional context in comments.

6 Comments

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...
Probably because you can't return void and Action also doesn't return anything.
But Action a = (x) => Bar(x); doesn't work either... (still says "Delegate 'Action' does not take 1 argument")
@Kjara Action<typeofparameterx> a = (x) => ..
I was confused. What I really wanted to do was this (which works): Action a = () => Bar("myString");. Thanks!
|
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.

Comments

1

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

Comments

1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.