0

In many ways C# supports functional programming, but there is a (shrinking) list of features commonly found in statically-typed functional languages that are missing, such as tail recursion, partial function application, etc. Of these missing features, partial application is "fake-able" using existing language features, although it is a bit wordy.

For example,

public static class Program {

    public static Func<T2, TResult> PartialApply(
        this Func<T1, T2, TResult> function, T1 arg1) {

        return t2 => function(arg1, t2);
    }

    static void Main() {

        Func<int, int, int> add = (x, y) => x + y;

        var add10 = add.PartialApply(10);

        var sum = add10(3); //Result is 13
    }
}

This works, although lack of type inference on delegates makes it a bit wordy. However, I don't recall ever seeing source code where C# is used in this way. I was kind of surprised it was absent in Tomas Petricek's book, which goes over many ways to use C# like F#.

Is there a reason (other than convention) that no one is doing this?


If anyone is interested, here is I made a T4 template that can generate PartialApply -type functions for as many arguments as you need by just editing a number.

  • 1
    It is sort of well-known. Jon Skeet, Mike Hadlow, etc. But it is not idiomatic C#. In C#, the idiomatic way is to define lambdas as you need it; ideally, define it at the point where another programmer looking at that piece of code will need to know exactly what will be executed when that lambda is executed. The reason is large-scale software development, not language aesthetics. – rwong Mar 28 '17 at 3:47
  • 1
    most languages that use PA often are also curried, which essentially gives you PA for free – jk. Mar 28 '17 at 8:28
  • I've seen tail call recursion in c# on windows 64 bit. I had a stack overflow on 32 bit windows that caused an infinite loop on 64 bit because of tail call recursion. – Mike Mar 28 '17 at 18:22
  • What you're describing sounds like using recursion without tail recursion being supported. – JamesFaix Mar 28 '17 at 21:15
2

This works, although lack of type inference on delegates makes it a bit wordy.

This is basically it. Partial application is wonderful for making expressions involving higher-order functions more readable. For example

 list.Filter(IsResident("Florida")).Map(YearsResidedIn("UnitedStates")).Sum()

Would read pretty well. On the contrary

list.Filter(PartiallyApply((Func<String, Customer, bool>)IsResident, "Florida").Map(PartiallyApply((Func<String, Customer, int>)YearsResidedIn, "UnitedStates").Sum()

reads terribly, indeed much worse than

list.Filter(c => IsResident("Florida", c).Map(c => YearsResidedIn("UnitedStates", c)).Sum()

Furthermore in C# you have many delegate types. So in addition to the one you defined you would need

Func<T2, T3, TResult> PartiallyApply<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> func, T1 arg)
Func<T3, TResult> PartiallyApply<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2)

Up to however many you can stomach to write plus a whole set of them for Action<>.

Basically, C# was really not designed for partial application. It does not feature the use of higher order functions nearly so heavily as a fully-fledged functional language, it has no inbuilt syntax partial application, it has a large set of delegate types that makes defining and using partial applications a pain, and even after you have defined your methods for partial application, you're going to have something more syntactically heavy and less readable than a plain old lambda expression.

  • See link of T4 template that generates to as many params as needed. – JamesFaix Mar 28 '17 at 4:56
  • I see your point, but your example doesn't show it with extension method syntax. It's a bit more fluent then, but you need to manually specify the type of the first delegate in the chain in scope somehow. The point it to avoid nested lambdas in some cases, not to entirely replace them. – JamesFaix Mar 28 '17 at 5:01
  • 1
    @JamesFaix, Sure, you can auto-generate the code and it's not a huge amount one way or another. But there's still the cost of the code being not built in (and hence an extra thing to learn) and the heavy syntactic cost of using it (namely you have to cast to a Func at some point and invoke the 15 characters of .PartiallyApply. Given this overhead and the limited opportunity to use it, I'm really struggling to understand why you would ever want this. – walpen Mar 28 '17 at 5:17
  • You'd have to see the codebase. There is already a lot of use of C# in non-idiomatic F#-like ways. I appreciate your feedback. – JamesFaix Mar 28 '17 at 16:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.