-
Notifications
You must be signed in to change notification settings - Fork 8
Function composition
Problem 1
> List.map ((flip (/) 4) >> negate) [1, 5, 12]
[-0.25,-1.25,-3] : List FloatIt's interesting to look at the error messages that come from removing parentheses. Here's the message from removing the outermost one:
> List.map (flip (/) 4) >> negate [1, 5, 12]The argument to function `negate` is causing a mismatch.
5| negate [1, 5, 12]
^^^^^^^^^^
Function `negate` is expecting the argument to be:
number
But it is:
List number
When parsing, >> has a low precedence, so that the line is interpreted as "compose the function produced by List.map ((flip (/) 4) with the function produced by negate [1, 5, 12]."
The error only happens when the compiler encounters negate because List.map ((flip (/) 4) is a perfectly valid function, formed by partially applying List.map. Here's an example of its use:
> divideContentByFour = List.map (flip (/) 4)
<function> : List Float -> List Float
> divideContentByFour [1, 5, 8]
[0.25,1.25,2] : List Float
> List.map divideContentByFour [ [1], [1, 2], [1, 2, 3]]
[[0.25],[0.25,0.5],[0.25,0.5,0.75]] : List (List Float)To see when the low precedence of >> can be useful, remove the parentheses from around ((flip (/) 4) in our original solution:
> List.map (flip (/) 4 >> negate) [1, 5, 12]
[-0.25,-1.25,-3] : List FloatHere, the partially-applied function is correctly composed with negate. So the parentheses aren't actually needed.
(You might be worried that you'll get the precedence wrong in a way that produces a valid pipeline, just not the one you wanted. I haven't reasoned through the problem to see if it's impossible, but it has to be pretty unlikely. Each step of the pipeline is an expression that produces a function. The value flowing through the pipeline is almost never a function. So a misparenthesization seems like it will always either produce a pipeline stage that's not a function or attempt to feed a value of type A into a function that expects type B. Both those cases must produce an error.)
Problem 2
[1, 5, 12] |> List.map (flip (/) 4) |> List.map negate
[-0.25,-1.25,-3] : List FloatProblem 3
> List.map (negate << (flip (/) 4)) [1, 5, 12]
[-0.25,-1.25,-3] : List Float
> List.map negate <| List.map (flip (/) 4) <| [1, 5, 12]
[-0.25,-1.25,-3] : List FloatProblem 4
List.map ( (4 |> flip (/)) >> negate) [1, 5, 12]I think it looks awful.