3

The F# pipe-forward can be expressed as:

let (|>) x f = f x

For example:

let SimpleFunction (a : typeA) (b : typeB) (c : typeC)=
    printf "OK."

// No problem here.
SimpleFunction a b c

// Using pipe-forward
c |> SimpleFunction a b
// No problem here. Interpreted as the same as above.

However, according to the documentation, the pipe-forward operator is left-associative.

https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/symbol-and-operator-reference/

So, I expected the pipe-forward statement:

// Original Expression
c |> SimpleFunction a b

// to be equivalent to:
(c |> SimpleFunction) a b

// Which is equivalent to:
SimpleFunction c a b
// Error!! SimpleFunction takes typeA, then typeB, then typeC.

Why does the compiler not "interpret" the pipe-forward expression as the error expression? Do I have any confusion about the operator precedence/associativity?


Additional Sources:

http://theburningmonk.com/2011/09/fsharp-pipe-forward-and-pipe-backward/

What is associativity of operators and why is it important?

https://en.wikipedia.org/wiki/Operator_associativity

aydinugur
  • 1,208
  • 2
  • 14
  • 21
CH Ben
  • 1,583
  • 13
  • 23

2 Answers2

10

The associativitity of a binary operator only matters when you have two or more occurrences of the same operator. When you have different operators (here: |> and juxtaposition), what matters is their relative precedence.

Juxtaposition has a higher precedence than |>, therefore

c |> SimpleFunction a b

is parsed like

(c) |> (SimpleFunction a b)

so, by the definition of |>, it's equivalent to

(SimpleFunction a b) (c)

which would usually be written

SimpleFunction a b c

That last equivalence is due to juxtaposition being left-associative.

The fact that |> is left-associative means that an expression like

x |> f |> g

is parsed as

(x |> f) |> g

which is equivalent to

g (f x)

i.e. chains of |> express function composition — successive pipeline steps — and not passing more arguments to a function.

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
0

Functions are curried by default, you original expression is actually like this:

c |> (SimpleFunction a b) which then becomes (SimpleFunction a b) c. For this to work function application will have to have precedence.

s952163
  • 6,276
  • 4
  • 23
  • 47