3

Just started learning F# and am currently reading "The Book Of F#". Maybe I am missing something but as far as I know forward/backward pipeline operators are passing the result of an expression into the last parameter of the next function in a forward/backward direction. But why does this work? It passes y to x (treating x as a function) first then pass x y into the last parameter e.g. b of minus. So it should return a closure not an int. But backwardTest 3 2 returns 1.

let backwardTest x y = 
    let minus a b = a - b
    minus <| x <| y
dragonfly02
  • 3,403
  • 32
  • 55
  • 1
    Operators, indeed, apply first argument first. Check [this question](http://stackoverflow.com/questions/11378402/partial-function-application-for-a-non-symmetric-operator-using-point-free-style) to see how we sometimes struggle to apply *non-first* one in case of asymmetric functions like subtraction, division, or modulus. – Be Brave Be Like Ukraine Dec 28 '15 at 11:30
  • Just re-checked the section about pipelining in the book I am reading and wish it had mentioned about this; otherwise it might be natural to think backward pipeline operator passes the arguments from right to left as well. Thanks for the link which clarifies things further! – dragonfly02 Dec 28 '15 at 11:38
  • The key is to stop thinking of these operators as something magic. They are just regular functions, like everything else. You can even define your own. In fact, that would be a useful exercise to understand what's going on. – Fyodor Soikin Dec 28 '15 at 12:24
  • @stt106, currying and partial application has pretty solid [mathematical background](http://stackoverflow.com/questions/36314/what-is-currying). And it is only about applying *first* or *first n* arguments. You can't uniformly apply *non-first* argument, since *non-first* may appear to be 2nd or 25th one. – Be Brave Be Like Ukraine Dec 28 '15 at 13:11
  • I think it is worth mentioning here that Don Syme, the creator of F#, recommends using the backward pipe operator very sparingly or not at all. – TeaDrivenDev Dec 28 '15 at 17:37
  • @TeaDrivenDev did he say why? – dragonfly02 Dec 28 '15 at 22:01
  • @stt106 because why would you want to type `minus <| x <| y` when you can just type `minus x y`? – phoog Dec 28 '15 at 22:19
  • @phoog, the problem with `<|` operator is its left associativity. I find it extremely useful for the purpose of eliminating parens, if it were converted into a high precedence, right associative backward pipe `^<|`, like in [this answer](http://stackoverflow.com/a/21093613/974789). – Be Brave Be Like Ukraine Jan 27 '16 at 05:48

1 Answers1

2

so you have

minus <| x <| y
=minus x <| y
=(minus x) y
=minus x y
John Palmer
  • 25,356
  • 3
  • 48
  • 67
  • Oh so the backward pipeline still passes expressions from left to right order? I thought it passes in the order of right to left. – dragonfly02 Dec 28 '15 at 10:38
  • 1
    No, the standard `<|` operator is still left associative, and for certain purposes, that is useful. For a right associative operator like Haskell's `$`, see [here](http://www.fssnip.net/4o). – TeaDrivenDev Dec 28 '15 at 17:39
  • 1
    @stt106 if `<|` were right associative, you would have a compile error because you cannot pass an int (y) to an int (x). Try `x |> y |> minus` if you don't understand what I mean, or even `minus <| (x <| y)`. – phoog Dec 28 '15 at 17:44
  • @phoog I think I understand what you mean but I still think `x |> y |> minus` complies fine though as F# can infer `y` as a function. Interestingly I have such a function to test the forward pipeline operator with exactly the same line and it compiles fine but it's doing what I want it to do. Or does this mean I didn't understand you? – dragonfly02 Dec 28 '15 at 21:58
  • @stt106 yes, it does compile fine by itself, inferring y as a function. However, the question implies that y is an int. That is, if we try `x |> y |> minus` in the function posted in the question, we can no longer call `backwardTest 3 2` because the argument supplied for y isn't, as expected by inference, a function. – phoog Dec 28 '15 at 22:10
  • @phoog Totally agree! Now I think I fully understand what you meant:) – dragonfly02 Dec 28 '15 at 22:18