How does F# pipeline operator work - f#

have a code:
//e = 1/2*Sum((yi -di)^2)
let error y d =
let map =
Array.map2 (fun y d -> (y - d) ** 2.0) y d
let sum =
Array.sum map
(sum / 2.0)
let error2 y d =
Array.map2 (fun y d -> (y - d) ** 2.0) y d
|> Array.sum
|> (/) 2.0
as i understood those functions should produce the same results, but there are a big difference in the results. Can anyone explain this?
p.s. Simplified example:
let test = [|1..10|]
let res = test
|> Array.sum
|> (/) 5
i expect test = 11 (sum(1..10) = 55 and then 55 / 5) but after Array.sum pipeline is not working as i want(as result test = 0).

another alternative is to use the reverse pipe operator (<|) so that partial application of (/) is done with arguments in correct order:
let error2 y d =
Array.map2 (fun y d -> (y - d) ** 2.0) y d
|> Array.sum
|> (/) <| 2.0
Edit: see if this helps clarify
x/y = (/) x y = y |> (/) x = x |> (/) <| y
All those are equivalent. The pipe operators are defined as:
(|>) x f = f x
(<|) f x = f x
where f is a function and x is some value. The reverse pipe doesn't look like it does much but it can help clean up some code in certain situations.

You seem to misunderstand order of arguments in infix functions.
You can expand the point-free form as follows:
x |> (/) 5
<=> (/) 5 x
<=> 5 / x
So it's is the reverse of what you expect. It only works fine for commutative functions like (+), (*), etc. If you're keen on point-free style, the flip function is helpful to be used with |>:
let inline flip f x y = f y x
let error2 y d =
Array.map2 (fun y d -> (y - d) ** 2.0) y d
|> Array.sum
|> flip (/) 2.0

The / operator does not work the way you have assumed. You just need to be a bit more explicit and change the last line in error2 to
fun t -> t/2.0
and then it should all work.
The answers being out by a factor of 4 was the giveaway here.
EDIT: To understand what happens with / here consider what happens when you expand out |>
The following are all equivalent
a |> (/) b
((/) b) a //by removing |>
a / b //what happens when / is reinterpreted as a function

Related

Is there a modulo equivalent for (<) in functions?

For example; the following line
|> Seq.filter(fun i -> i < 123)
is the same thing as
|> Seq.filter((<) 123)
Is there such a thing for the modulo operator? I'm not sure what the 2nd variant is, and can't find it referenced in the documentation either, so it makes searching somewhat difficult. So for bonus points, please tell me what this operator is called! :)
Currently using:
|> Seq.filter (fun i -> i % 2 = 0)
Looking for something like:
|> Seq.filter ((%) 2 = 0)
Your first example is incorrect in saying that fun i -> i < 123 is equal to ((<) 123). That is actually equivalent to fun i -> 123 < i. Let me explain, every operator is just a function but infix rather than prefix. As an example
let (+) x y = x + y
let add x y = x + y
let (-) a b = a - b // notice that the first argument (a) is on the left side of the operator
let subs a b = a - b
knowing this, we can then reason about % and < the same way
let (%) x y = x % y
let (<) x y = x < y
// therefore
fun i -> i < 123
// is equivalent to
fun i -> (<) i 123
// and mathematically equiv to
((>=) 123)
// same with %
fun i -> i % 2
// is equiv to
fun i -> (%) i 2
// thus cant be reduced to eliminate the lambda
Another alternative, if you're dead-set on not writing out the lambda, is to lift it into a function:
let inline isEven x = x % 2 = 0
...
|> Seq.filter isEven
Alas, you are out of luck, because for partial application to be suitable, you need to swap both arguments of the mod operator. The lambda function is way more concise when taking into account that you are applying two operators, which requires function composition.
let flip f a b = f b a
{0..9}
|> Seq.filter ((flip (%) 2) >> ((=) 0))
|> (Seq.map string >> String.concat ", ")
// val it : string = "0, 2, 4, 6, 8"

Pipe Right pass-through operator PipeThrough

I have declared the following operator to help make my curried code a bit more legible
Pipe-Through allows a value to be passed through a method and continue out the other side. I think it helps make my code more succinct.
let (|>!) x f = x |> f |> ignore; x
Example of use
let y = x |> transform
y |> logger.LogInformation
y
|> process
|> return
Now becomes
x
|> transform
|>! logger.LogInformation
|> process
|> return
Is this useful or have I reinvented the wheel
It is useful and like all good inventions it has been independently made by others as well.
Scott Wlaschin called it tee: https://fsharpforfunandprofit.com/rop/
The proposed operator is |>!:
let inline tee f v = f v ; v
let inline (|>!) v f = f v ; v
let inline (>>!) g f = g >> fun v -> f v ; v /// composition
(5 * 8) |> tee (printfn "value = %d") |> doSomethingElse
(5 * 8) |>! printfn "value = %d" |> doSomethingElse
This definition is slightly different than yours as it does not use ignore.
Thanks for sharing!

How to forward pipe a value to the left side parameter of a function?

For example,
let fn x y = printfn "%i %i" x y
1 |> fn 2 // this is the same as fn 2 1 instead of fn 1 2
How to make it fn 1 2?
This is just a simplified example for test. I have a complex function return a value and I want to forward pipe it to the left side (in stead of right side) of a function.
I assume that you have at least two pipes. Otherwise, fn 1 2 does the job; why should we make it more complicated?
For commutative functions (which satisfy f x y = f y x) such as (+), (*), etc. you can just use 1 |> fn 2.
For other functions, I can see a few alternatives:
Use backward pipes
arg1
|> fn1
|> fn2 <| arg2
I tend to use this with care since operators' precedence might cause some subtle bugs.
Use flip function
let inline flip f x y = f y x
Array.map2 (fun y d -> (y - d) ** 2.0) y d
|> Array.sum
|> flip (/) 2.0
It's not pretty but it's clear that order of arguments in (/) is treated differently.
Use anonymous functions with fun and function keywords
This is handy if you need pattern matching in place.
input
|> createOption
|> function None -> 0 | Some _ -> 1
IMO, you don't have to pipe all the way. Create one more let binding, then your intention is clear and you can avoid bugs due to unusual styles.
let sum =
Array.map2 (fun y d -> (y - d) ** 2.0) y d
|> Array.sum
sum / 2.0
Here is a solution that looks pretty. I don't know if it is too practical though
1 |> fn <| 2

Why does the pipe operator work?

If the pipe operator is created like this:
let (|>) f g = g f
And used like this:
let result = [2;4;6] |> List.map (fun x -> x * x * x)
Then what it seems to do is take List.Map and puts it behind (fun x -> x * x * x)
And doesn't change anything about the position of [2;4;6]
So now it looks like this:
let result2 = [2;4;6] (fun x -> x * x * x) List.map
However this doesn't work.
I am just learning f# for the first time now. And this bothered me while reading a book about f#. So I might learn what I'm missing later but I decided to ask anyway.
It is obvious though that I am missing something major. Since I can easily recreate the pipe operator. But I don't get why it works. I might embarrass myself very soon as I learn more. Oh well.
The pipe operator is simply syntactic sugar for chained method calls. It's very similar to how linq expressions are expressed in C#.
Explanation from here:
Forward Pipe Operator
I love this guy. The Forward pipe operator is simply defined as:
let (|>) x f = f x
And has a type signature:
'a -> ('a -> 'b) -> 'b
Which translates to: given a generic type 'a, and a function which takes an 'a and returns a 'b, then return the application of the function on the input.
Rather than explaining this, let me give you an example of where it can be used:
// Take a number, square it, then convert it to a string, then reverse that string
let square x = x * x
let toStr (x : int) = x.ToString()
let rev (x : string) = new String(Array.rev (x.ToCharArray()))
// 512 -> 1024 -> "1024" -> "4201"
let result = rev (toStr (square 512))
The code is very straight forward, but notice just how unruly the syntax looks. All we want to do is take the result of one computation and pass that to the next computation. We could rewrite it by introducing a series of new variables:
let step1 = square 512
let step2 = toStr step1
let step3 = rev step2
let result = step3
But now you need to keep all those temporary variables straight. What the (|>) operator does is take a value, and 'forward it' to a function, essentially allowing you to specify the parameter of a function before the function call. This dramatically simplifies F# code by allowing you to pipe functions together, where the result of one is passed into the next. So to use the same example the code can be written clearly as:
let result = 512 |> square |> toStr |> rev
Edit:
In F# what you're really doing with a method call is taking a function and then applying it to the parameter that follows, so in your example it would be List.map (fun x -> x * x * x) is applied to [2;4;6]. All that the pipe operator does is take the parameters in reverse order and then do the application reversing them back.
function: List.map (fun x -> x * x * x)
parameter: [2;4;6]
Standard F# call syntax: f g
Reversed F# call syntax: g f
Standard:
let var = List.map (fun x -> x * x * x) [2;4;6]
Reversed:
let var = [2;4;6] |> List.map (fun x -> x * x * x)
The brackets around |> mean it is an infix operator so your example could be written
let result = (|>) [2;4;6] (List.map (fun x -> x * x * x))
Since |> applies its first argument to the second, this is equivalent to
let result = (List.map (fun x -> x * x)) [2;4;6]
As others have said above, basically you're misunderstanding what result2 would resolve to. It would actually resolve to
List.map (fun x -> x * x * x) [2;4;6]
List.map takes two arguments: a function to apply to all elements in a list and a list. (fun x -> x * x * x) is the first argument and [2;4;6] is the second.
Basically just put what's on the left of |> after the end of what's on the right.
If you enter your definition of |> into fsi and look at the operator's signature derived by type inference you'll notice val ( |> ) : 'a -> ('a -> 'b) -> 'b, i.e. argument 'a being given to function ('a -> 'b) yields 'b.
Now project this signature onto your expression [2;4;6] |> List.map (fun x -> x * x * x) and you'll get List.map (fun x -> x * x * x) [2;4;6], where the argument is list [2;4;6] and the function is partially applied function of one argument List.map (fun x -> x * x * x).

Piping another parameter into the line in F#

Is piping parameter into line is working only for functions that accept one parameter?
If we look at the example at Chris Smiths' page,
// Using the Pipe-Forward operator (|>)
let photosInMB_pipeforward =
#"C:\Users\chrsmith\Pictures\"
|> filesUnderFolder
|> Seq.map fileInfo
|> Seq.map fileSize
|> Seq.fold (+) 0L
|> bytesToMB
where his filesUnderFolder function was expecting only rootFolder parameter,
what if the function was expecting two parameters, i.e.
let filesUnderFolder size rootFolder
Then this does not work:
// Using the Pipe-Forward operator (|>)
let size= 4
let photosInMB_pipeforward =
#"C:\Users\chrsmith\Pictures\"
|> filesUnderFolder size
|> Seq.map fileInfo
|> Seq.map fileSize
|> Seq.fold (+) 0L
|> bytesToMB
Since I can define
let inline (>>) f g x y = g(f x y)
I think I should be able to use pipeline operator with functions having multiple input parameters, right? What am I missing?
When mixing pipeline operators and curried arguments be aware of the order you pass arguments with.
let size = 4
let photosInMB_pipeforward =
size, #"C:\Users\chrsmith\Pictures\"
||> filesUnderFolder
|> Seq.map fileInfo
|> Seq.map fileSize
|> Seq.fold (+) 0L
|> bytesToMB
Think about it as if the compiler is putting parentheses around the function and its parameters like this.
#"C:\Users\chrsmith\Pictures\" |> filesUnderFolder size
becomes
#"C:\Users\chrsmith\Pictures\" |> (filesUnderFolder size)
or
(filesUnderFolder size) #"C:\Users\chrsmith\Pictures\"
Out of order example
let print2 x y = printfn "%A - %A" x y;;
(1, 2) ||> print2;;
1 - 2
1 |> print2 2;;
2 - 1
With three arguments
let print3 x y z = printfn "%A - %A - %A" x y z;;
(1, 2, 3) |||> print3;;
1 - 2 - 3
(2, 3) ||> print3 1;;
1 - 2 - 3
3 |> print3 1 2;;
1 - 2 - 3
Definitions
let inline (|>) x f = f x
let inline (||>) (x1,x2) f = f x1 x2
let inline (|||>) (x1,x2,x3) f = f x1 x2 x3
The example you suggested should work fine, a la
let add x y = x + y
41
|> add 1
|> printfn "%d"
If filesUnderFolder takes two curried args, and you partially apply it to one arg, you can use it in the pipeline for the other.
(Note also the lesser known pipeline operator ||>
(41,1)
||> add
|> printfn "%d"
which takes a 2-tuple and feed them sequentially into what follows.)
It may be bad style (?), but you can add additional parameters to the pipeline 'from the right side'
let h x y z = x + y - z
let sub x y = x - y
let sqr x = x * x
3 |> h <| 2 <| 7
|> sub <| 23
|> sqr
// is the same as
sqr (sub (h 3 2 7) 23)

Resources