5

Every time I write something of the form

let scorePopulation f population =
  Array.map (fun i -> f i) population

I end up asking myself if wouldn't I be better writing

let scorePopulation f =
  Array.map (fun i -> f i)

instead. Is there any advantage of writing it in the first form as opposed to the second?

Also, how would you call a function definition in the first form and in the second form?

6 Answers 6

12

You could go even further:

let scorePopulation = Array.map

In terms of advantages/disadvantages, I think that the main concern will typically be readability. Sometimes it's easier to understand what a function does when all of the arguments are present. Other times, the fact that you don't need to make up extraneous variable names wins out.

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

2 Comments

+1 for mentioning naming. It's a mental speed bump when coding.
+1 as well. My answer basically says the same thing but coming from a different direction. Names are expensive, don't waste them on irrelevant things, but do give them to relevant things.
10

Actually, the pros and cons are the same: naming.

The reason for this is the old saying by Phil Karlton:

There are only two hard problems in computer science. Cache invalidation and naming things.

If naming things is hard (i.e. expensive), then names shouldn't be wasted on irrelevant things. And conversely, if something has a name, then it is important.

Point-free style allows you to omit names.

The pro is that it allows you to omit irrelevant names.

The con is that it allows you to omit relevant names.

Comments

7

I would argue partial application is a benefit of functional programming. Why not take advantage of it? It results in less redundancy.

Another thing to keep in mind is value restriction[MSDN]. A partially-applied function without parameters is a function value. True functions can be generalized, but values cannot.

Comments

6

You should be able to call it in just the same way in the first and second example. This technique is typically called point-free style.

It might be better. It's shorter, so that's a plus by default. I agree with this warning from the link above:

As higher-order functions are chained together, it can become harder to mentally infer the types of expressions. The mental cues to an expression's type (explicit function arguments, and the number of arguments) go missing.

You also lose the opportunity to give the parameter a meaningful name, which might sometimes aid understanding.

Comments

5

Personally I hate point-free style, I always find it unreadable. As someone else mentioned,

You also lose the opportunity to give the parameter a meaningful name, which might sometimes aid understanding.

Overall, if I am defining a named function on the left, I usually want to see all the 'expected' params listed. (In contrast, partial application is great for anonymous call sites and local lambdas, but I like more explicitness/documentation when authoring top-level code - the larger the scope, the more 'software engineering' concerns play in.)

As someone else mentioned, the 'value restriction' kicks in if you get rid of all the parameters from a generic function, which is a technical limitation which also minorly discourages point-free style in F#.

3 Comments

If Intellisense would include arg names with the signatures, point-free style would be more palatable. You could hover over the function and see (arg1:int -> arg2:int -> int).
What do you get when you hover over h in let h = if someCond then f else g where f and g are functions with the same type but different argument names? (More generally, argument names do not 'flow' through the existing type system in any meaningful way, so there are technical challenges to implement this, even if you overcome the design question I posed in the previous sentence.)
In that case, fallback to the current approach? For simple and partially-applied functions (the majority?) mightn't it be possible? It feels like a form of generalization. In your example, the most specific signature contains only types.
2

I often provide the parameter even if I could omit it for clarity. When I omit the parameter it is usually because the function body immediately makes it obvious: i) that there is an omitted parameter and ii) what the nature of the parameter is. For example, I find it sufficient to write

let f = function [] -> "empty" | x::_ -> "not empty"

instead of

let f l = match l with [] -> "empty" | x::_ -> "not empty"

A more interesting example is to write

let f = List.map g |> List.fold_left h

instead of

let f l = List.map g (List.fold_left h l)

I find the first one more clear. The benefit here arises from the availability of intuitive higher-order operators such as |>, which is provided in Batteries.

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.