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?开发者_JAVA技巧
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.
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.
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.
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.
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#.
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.
精彩评论