To Pipe or Not to Pipe? - f#

That is (sort of) the question.
I'm trying to learn F# more lately and my resources seem to prefer piping in places where it's not clear a benefit exists. For example, given a function in curried form:
f: a -> b -> c -> R
I can call it by supplying all the arguments inline or pipe c in like so:
let r = f a b c
let r = c |> f a b
But is there a cost or benefit or is it purely a stylistic preference?

There should be no cost.
UPDATE
There may be some extra cost.
Sometimes an extra call is inserted, but some other times the compiler can optimize it avoiding the extra call.
I tested the following code:
let concat (a:string) (b:string) = System.String.Concat(a, b)
let f1 g a c = g a c
let f2 g a c = c |> g a
f1 concat "b" "c" \\ 00:00:33.8895616
f2 concat "b" "c" \\ 00:00:34.6051700
concat "b" "c" \\ 00:00:35.0669532
"c" |> concat "b" \\ 00:00:35.1948296
f1 (+) "b" "c" \\ 00:00:35.4796687
f2 (+) "b" "c" \\ 00:00:49.3227193
(+) "b" "c" \\ 00:00:35.0689207
"c" |> (+) "b" \\ 00:00:35.8214733
For each case I performed a billion calls (1_000_000_000) and those were the times. As you can see only calling f2 (+) "b" "c" was slower than the rest which may have something to do with (+) being an operator that uses SRTP.
Thanks to #PhillipCarter for clarifying.
The use of pipe helps with type inference:
let words = "many words".Split ' '
let wordsU1 = words |> Array.map (fun w -> w.ToUpper()) // ok
wordsU1 |> Seq.iter (printfn "words are %A")
let wordsU2 = Array.map (fun w -> w.ToUpper()) words // type annotation needed: (w:string)
Seq.iter (printfn "words are %A") wordsU2
The two calls to Array.map are equivalent but the second one complains that it does not know the type of w. That is because F# type inference mechanism works from left to right and in the second case words is after the lambda function.
It is also better stylistically. The code above can be better expressed like this:
"many words".Split ' '
|> Array.map (fun w -> w.ToUpper())
|> Seq.iter (printfn "words are %A")
So the pipe can be used to chain several expressions without having to use parenthesis or binding it to names.

Pipe. Don Syme loves pipelines (proof) :)
Also remember there are ||> and |||> pipes as well.

Related

Better way to sum rows

I'm learning F# (again) and I'm trying to sum some rows in excel. This is my attempt.
let sumRows (source: seq<double[]>) =
source
|> Seq.reduce (fun a b -> (a, b) ||> Seq.map2 (fun x y -> x + y) |> Seq.toArray)
Can it be done better? I already discovered double forward pipe operator, but now, whole part fun a b -> (a, b) ||> seems quite redundant...
You are right it is redundant, because the double pipe operator is convenient only when you need to convert a tuple into two separate parameters. In this case you already have them as 2 separate parameters so you could just pass them like this:
let sumRows (source: seq<double[]>) =
source
|> Seq.reduce (fun a b -> Seq.map2 (fun x y -> x + y) a b |> Seq.toArray)
We can get rid of the |> Seq.toArray by replacing Seq.map2 with Array.map2:
let sumRows (source: seq<double[]>) =
source
|> Seq.reduce (fun a b -> Array.map2 (fun x y -> x + y) a b)
now we can simplify further by removing the fun a b ->:
let sumRows (source: seq<double[]>) =
source
|> Seq.reduce (Array.map2 (fun x y -> x + y) )
Finally, did you know that an operator like + can be treated as a 2 parameters function
by putting in parenthesis (+)?
let sumRows2 (source: seq<double[]>) =
source
|> Seq.reduce (Array.map2 (+) )
All of this versions have the same signature and they are all correct. You choose whichever suits more your style.
BTW, you maybe tempted to go one further and do this:
let sumRows2 = Seq.reduce (Array.map2 (+) )
but it causes issues with the famous Value restriction error. There are workarounds like adding the type annotation or actually using it somewhere in the code, but the best workaround is to add the parameter, like we had before.

Get even numbers with composition

I can obtain the even numbers in a list using the lambda syntax:
[1..10] |> List.filter (fun x -> x % 2 = 0)
But I want get it with composition, like this:
[1..10] |> List.filter ((% 2) >> (= 0))
Error: stdin(7,37): error FS0010: Unexpected integer literal in expression. Expected ')' or other token.
F# does not support operator sections. You can partially apply an operator by enclosing it in parentheses, like so:
let five = (+) 2 3
let add2 = (+) 2
let alsoFive = add2 3
However, this will not allow you to partially apply the right argument of the operator. In other words, F# does not offer anything equivalent to Haskell expression (/ 2). This can be worked around for commutative operators, such as addition or multiplication, because (+ 2) === (2 +), which in F# can be expressed as ((+) 2), but not for non-commutative ones.
The best you can do is declare the section as a separate function, like this:
let mod2 x = x % 2
[1..10] |> List.filter (mod2 >> ((=) 0))
If you absolutely insist on not declaring any more functions, you could try to do with a flip:
[1..10] |> List.filter ((flip (%) 2) >> ((=) 0))
But sadly, F# standard library does not provide a flip function either, so you'd have to declare it yourself anyway:
let inline flip f a b = f b a
Personally, I would rather go for increased readability and declare an isEven function:
let isEven x = (x % 2) = 0
[1..10] |> List.filter isEven

How do I do in F# what would be called compression in APL?

In APL one can use a bit vector to select out elements of another vector; this is called compression. For example 1 0 1/3 5 7 would yield 3 7.
Is there a accepted term for this in functional programming in general and F# in particular?
Here is my F# program:
let list1 = [|"Bob"; "Mary"; "Sue"|]
let list2 = [|1; 0; 1|]
[<EntryPoint>]
let main argv =
0 // return an integer exit code
What I would like to do is compute a new string[] which would be [|"Bob"; Sue"|]
How would one do this in F#?
Array.zip list1 list2 // [|("Bob",1); ("Mary",0); ("Sue",1)|]
|> Array.filter (fun (_,x) -> x = 1) // [|("Bob", 1); ("Sue", 1)|]
|> Array.map fst // [|"Bob"; "Sue"|]
The pipe operator |> does function application syntactically reversed, i.e., x |> f is equivalent to f x. As mentioned in another answer, replace Array with Seq to avoid the construction of intermediate arrays.
I expect you'll find many APL primitives missing from F#. For lists and sequences, many can be constructed by stringing together primitives from the Seq, Array, or List modules, like the above. For reference, here is an overview of the Seq module.
I think the easiest is to use an array sequence expression, something like this:
let compress bits values =
[|
for i = 0 to bits.Length - 1 do
if bits.[i] = 1 then
yield values.[i]
|]
If you only want to use combinators, this is what I would do:
Seq.zip bits values
|> Seq.choose (fun (bit, value) ->
if bit = 1 then Some value else None)
|> Array.ofSeq
I use Seq functions instead of Array in order to avoid building intermediary arrays, but it would be correct too.
One might say this is more idiomatic:
Seq.map2 (fun l1 l2 -> if l2 = 1 then Some(l1) else None) list1 list2
|> Seq.choose id
|> Seq.toArray
EDIT (for the pipe lovers)
(list1, list2)
||> Seq.map2 (fun l1 l2 -> if l2 = 1 then Some(l1) else None)
|> Seq.choose id
|> Seq.toArray
Søren Debois' solution is good but, as he pointed out, but we can do better. Let's define a function, based on Søren's code:
let compressArray vals idx =
Array.zip vals idx
|> Array.filter (fun (_, x) -> x = 1)
|> Array.map fst
compressArray ends up creating a new array in each of the 3 lines. This can take some time, if the input arrays are long (1.4 seconds for 10M values in my quick test).
We can save some time by working on sequences and creating an array at the end only:
let compressSeq vals idx =
Seq.zip vals idx
|> Seq.filter (fun (_, x) -> x = 1)
|> Seq.map fst
This function is generic and will work on arrays, lists, etc. To generate an array as output:
compressSeq sq idx |> Seq.toArray
The latter saves about 40% of computation time (0.8s in my test).
As ildjarn commented, the function argument to filter can be rewritten to snd >> (=) 1, although that causes a slight performance drop (< 10%), probably because of the extra function call that is generated.

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

In F# what does the >> operator mean?

I noticed in some code in this sample that contained the >> operator:
let printTree =
tree >> Seq.iter (Seq.fold (+) "" >> printfn "%s")
What does the >> operator mean/do?
EDIT:
Thanks very much, now it is much clearer.
Here's my example I generated to get the hang of it:
open System
open System.IO
let read_lines path = File.ReadAllLines(path) |> Array.to_list
let trim line = (string line).Trim()
let to_upper line = (string line).ToUpper()
let new_list = [ for line in read_lines "myText.txt" -> line |> (trim >> to_upper) ]
printf "%A" new_list
It's the function composition operator.
More info on Chris Smith's blogpost.
Introducing the Function Composition
operator (>>):
let inline (>>) f g x = g(f x)
Which reads as: given two functions, f
and g, and a value, x, compute the
result of f of x and pass that result
to g. The interesting thing here is
that you can curry the (>>) function
and only pass in parameters f and g,
the result is a function which takes a
single parameter and produces the
result g ( f ( x ) ).
Here's a quick example of composing a
function out of smaller ones:
let negate x = x * -1
let square x = x * x
let print x = printfn "The number is: %d" x
let square_negate_then_print = square >> negate >> print
asserdo square_negate_then_print 2
When executed prints ‘-4’.
The >> operator composes two functions, so x |> (g >> f) = x |> g |> f = f (g x). There's also another operator << which composes in the other direction, so that (f << g) x = f (g x), which may be more natural in some cases.
The composition operators, << and >> are use to join two functions such that the result of one becomes the input of the other. Since functions are also values, unless otherwise note, they are treated as such so that the following expressions are equivalent:
f1 f2 f3 ... fn x = (..((f1 f2) f3) ... fn) x
Specifically, f2, f3, ...fn and x are treated as values and are not evaluated prior to being passed as parameters to their preceding functions. Sometimes that is what you want but other times you want to indicate that the result of one function is to be the input of the other. This can be realized using the composition operators << and >> thus:
(f1 << f2 << f3 ... << fn) x = f1(f2(f3 ... (fn x )..)
Similarly
(fn >> ... f3 >> f2 >> f1) x = f1(f2(f3 ... (fn x )..)
Since the composition operator returns a function, the explicit parameter, x, is not required unlike in the pipe operators x |> fn ... |> f1 or f1 <| ... fn <| x
According to F# Symbol and Operator Reference it is Forward Function Composition operator.
That is function composition, used for partial application

Resources