4

I stumbled upon this answer in codegolf.stackexchange.com where they talk about point-free programming. The following was an code example.

instead of

    foo.Select(x=>int.Parse(x))

you can use

    foo.Select(int.Parse)

Questions:

  1. How does Select()know how to pass the variable into int.Parse()?

  2. Is the point-free technique limited to Linq/Select or can other methods use it aswell?

  3. How can I implement this into my own C# functions? Would love some examples.

  • 1
    I would argue that your provided example is not in fact point-free as would be in functional language like Haskell. It is simply just a compiler shortcut. And that truly point-free style is not possible in C# due to lack of primitives for functional composition. – Euphoric Jun 10 at 9:10
  • 5
    Why the downvote? It is not me who claims the code is point-free. I think it is clear that I want to learn more about the technique and in the concept of passing parameters automatically, as in the example. If there is something unclear or problematic about the question please let me know. – David Jun 10 at 9:16
  • @Euphoric You can make these "primitives" if you want using implicit operators (however well-designed that may be), and then you get reasonably nice function composition (barring multiple argument support, which would have to be solved using tuples). – ThreeFx Jun 10 at 9:27
  • "How does Select()know how to pass the variable into int.Parse()?" - because int.Parse takes a parameter, of course – user253751 Jun 10 at 19:26
  • @user253751 Yeah I got that. What I really meant to ask is: In C# you always specify the parameter(s) but not in this case. I was intrigued and wanted to learn more. Thats all... – David Jun 10 at 20:56
10

I would argue that your provided example is not in fact point-free as would be in functional language like Haskell. It is simply just a compiler shortcut. And that truly point-free style is not possible in C# due to lack of primitives for functional composition.

The heuristic of "there is no mention of function parameters" is not the exact definition of the term. As explained here, it is about how multiple functions are called together.

Lets say you have two functions f(A)->B and g(B)->C and you want to call them one after the other. In normal situation, you would call the first method, save it's result and then pass the result to the second one :

B = f(A)
C = g(B)

or simplified:

C = g(f(A))

Both above are equivalent. point-free style would be different in that instead of calling the two functions, you first compose the functions into a third function h(A)->C and then call that:

h = f . g // here . is function composition operator that C# lacks
C = h(A)

No such thing is happening in your C# code. The two parts are identical in 'style' and first one just contains a one more level of indirection:

foo.Select(x=>int.Parse(x))

is equivalent to

int anonymous_compiler_generated_method(string x)
{
    return int.Parse(x);
}

foo.Select(anonymous_compiler_generated_method)

Which is not that different from

foo.Select(int.Parse)

If I were to use Haskell for comparison, I would call this example a trivial usage of higher-order functions.

| improve this answer | |
  • Does "function composition" fundamentally just entail another overarching method being generated (whose type is A -> C), which performs the work of evaluating one method then passing the value to the next? That is h(A) is a wrapper method around g(f(A))? So a point-free style assumes the compatibility of the type and adicity of one function's output and the next's input. The OP gives not an example of a point-free style, but the distinction between passing the function pointer of an existing method (int.Parse), and passing the function pointer of an anonymous wrapper method for that. – Steve Jun 10 at 13:52
  • very minor points: You can do function composition in C# but, it's ugly (nothing like a single .) and almost no one does it. F#, of course, provides it (apparently with >> ), but it's a... peer?... of Haskell – Reginald Blue Jun 10 at 20:22
  • 2
    Why does it matter whether it's the compiler that is removing the point x from the code? – Bergi Jun 10 at 21:06
  • I can easily write a Compose extension method in C# that allows me to do foo.Select( ParseInt.Compose(SquareInt)). Apart from the annoyance that ParseInt has to already be a Func, how is this not C# supporting point-free function composition? Getting some huge "Haskell Master Race" vibes from this post. – Carl Leth Jun 16 at 0:28
3

How does Select know how to pass the variable into int.Parse

Select is approximately

IEnumerable<U> Select(this IEnumerable<T> source, Func<T, U> proj) {
    foreach (T obj in source) yield proj(obj);
}

It doesn't deal in the variable, but a sequence of values. Other types that have Select have similar meanings

async Task<U> Select(this Task<T> source, Func<T, U> proj) {
    return proj(await source);
}

Is the point-free technique limited to Linq/Select or can other methods use it aswell?

You can use it whereever you wish to initialise a Func from a function, you don't need a lambda to wrap it.

As noted in the comments, this isn't really point-free in the same way as in Haskell, where you can define a function without naming it's parameters.

Here it is a syntax for initialising a variable from a value.

How can I implement this into my own C# functions?

Have functions with Func or Action parameters

| improve this answer | |
  • "you can define a function without naming it's parameters." - is it not possible in C# to declare a variable of type Func and assign it the result of a helper function such as compose? – Bergi Jun 10 at 21:10
1

The short answers to your questions would be:

  1. The compiler does something called type inference, which it uses to figure out types you did not explicitly specify. This is also what happens when you use var instead of an actual variable name. The standard algorithm for this is called Hindley-Milner, and it has to do with a computation model called the typed lambda calculus.

  2. You can use it anywhere a Func is used, for example

int Plus1(int x) { return x + 1; }

Func<int, int> plus1 = x => Plus1(x);
Func<int, int> _plus1 = Plus1;
  1. Don't. Its not a good idea to force a style from a different language on your language, as the code becomes difficult to read and difficult to maintain. FWIW you can integrate other primitives and emulate writing point-free code, but it's more of a fun party trick than anything else:
using System.IO;
using System;
using System.Linq;

class Program
{
    static void Main()
    {
        var ls = Enumerable.Range(1, 10).Select<int, int>(new Compose<int, int, int>(y => y+1, y => y * 2));
        foreach (int l in ls) {
            Console.WriteLine(l);
        }
    }
}

class Compose<A, B, C> {
    Func<A, B> f;
    Func<B, C> g;

    public Compose(Func<A, B> f, Func<B, C> g) {
        this.f = f;
        this.g = g;
    }

    public static implicit operator Func<A, C>(Compose<A, B, C> c) {
        return x => c.g(c.f(x));
    }
}

The terms point-free and η-reduction come from functional programming, and while C# tries (and mostly succeeds) in presenting a functional API for programmers, there are some fundamental differences between it and functional languages.

I'd suggest you read up on the lambda calculus, which is the model of computation where these two terms originally stem from.

| improve this answer | |

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.