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)
Related
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!
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
How can I create a partial function application for a non-symmetric operator such as the modulus operator with regards to the first argument without any argument names in F#? My first attempt was
let mod10 = (%) 10 which of course translates to
mod10(x) = 10 mod x instead of the desired
mod10(x) = x mod 10.
Certainly I could write
let mod10 x = (%)x 10 but I'd like to not have to name the argument so is there some placeholder that can be used, something like
let mod10 = (%)_ 10?
Here's solution based on functional composition.
let mod10 = (%) >> (|>) 10
UPD Here was a wordy explanation, but programmers speak the code, so I guess the following will describe it much better, in a manner of mathematical proof.
The following expressions are equal:
let m1 x = x % 10
let m2 x = (%) x 10 // x (op) y = (op) x y
let m3 x = ((%) x) 10 // f x y = (f x) y
let m4 x = 10 |> ((%) x) // f x = x |> f
let m5 x = ((|>) 10) ((%) x) // x |> f = (|>) x f
let m6 x = ((%) x) |> ((|>) 10) // f x = x |> f
let m7 x = (x |> (%)) |> ((|>) 10) // (op) x = x |> (op)
let m8 x = x |> ((%) >> ((|>) 10)) // f(x) |> g = x |> (f >> g)
let m9 = (%) >> ((|>) 10) // remove formal argument
let m10 = (%) >> (|>) 10 // remove unnecessary parenthesis
Alternative syntax:
let mod10_2 = (|>) 10 << (%)
You can define flip function which is common in point-free style:
let inline flip f x y = f y x
and use it like this:
let (%-) = flip (%)
let mod10 = (%-) 10
or directly like this:
let mod10 = flip (%) 10
Point-free style is not always readable (as in this example) and not popular in F# programming.
Hullo all.
I am a C# programmer, exploring F# in my free time. I have written the following little program for image convolution in 2D.
open System
let convolve y x =
y |> List.map (fun ye -> x |> List.map ((*) ye))
|> List.mapi (fun i l -> [for q in 1..i -> 0] # l # [for q in 1..(l.Length - i - 1) -> 0])
|> List.reduce (fun r c -> List.zip r c |> List.map (fun (a, b) -> a + b))
let y = [2; 3; 1; 4]
let x = [4; 1; 2; 3]
printfn "%A" (convolve y x)
My question is: Is the above code an idiomatic F#? Can it be made more concise? (e.g. Is there some shorter way to generate a filled list of 0's (I have used list comprehension in my code for this purpose)). Any changes that can improve its performance?
Any help would be greatly appreciated. Thanks.
EDIT:
Thanks Brian. I didn't get your first suggestion. Here's how my code looks after applying your second suggestion. (I also abstracted out the list-fill operation.)
open System
let listFill howMany withWhat = [for i in 1..howMany -> withWhat]
let convolve y x =
y |> List.map (fun ye -> x |> List.map ((*) ye))
|> List.mapi (fun i l -> (listFill i 0) # l # (listFill (l.Length - i - 1) 0))
|> List.reduce (List.map2 (+))
let y = [2; 3; 1; 4]
let x = [4; 1; 2; 3]
printfn "%A" (convolve y x)
Anything else can be improved? Awaiting more suggestions...
As Brian mentioned, the use of # is generally problematic, because the operator cannot be efficiently implemented for (simple) functional lists - it needs to copy the entire first list.
I think Brians suggestion was to write a sequence generator that would generate the list at once, but that's a bit more complicated. You'd have to convert the list to array and then write something like:
let convolve y x =
y |> List.map (fun ye -> x |> List.map ((*) ye) |> Array.ofList)
|> List.mapi (fun i l -> Array.init (2 * l.Length - 1) (fun n ->
if n < i || n - i >= l.Length then 0 else l.[n - i]))
|> List.reduce (Array.map2 (+))
In general, if performance is an important concern, then you'll probably need to use arrays anyway (because this kind of problem can be best solved by accessing elements by index). Using arrays is a bit more difficult (you need to get the indexing right), but perfectly fine approach in F#.
Anyway, if you want to write this using lists, then here ara some options. You could use sequence expressions everywhere, which would look like this:
let convolve y (x:_ list) =
[ for i, v1 in x |> List.zip [ 0 .. x.Length - 1] ->
[ yield! listFill i 0
for v2 in y do yield v1 * v2
yield! listFill (x.Length - i - 1) 0 ] ]
|> List.reduce (List.map2 (+))
... or you can also combine the two options and use a nested sequence expression (with yield! to generate zeros and lists) in the lambda function that you're passing to List.mapi:
let convolve y x =
y |> List.map (fun ye -> x |> List.map ((*) ye))
|> List.mapi (fun i l ->
[ for _ in 1 .. i do yield 0
yield! l
for _ in 1 .. (l.Length - i - 1) do yield 0 ])
|> List.reduce (List.map2 (+))
The idiomatic solution would be to use arrays and loops just as you would in C. However, you may be interested in the following alternative solution that uses pattern matching instead:
let dot xs ys =
Seq.map2 (*) xs ys
|> Seq.sum
let convolve xs ys =
let rec loop vs xs ys zs =
match xs, ys with
| x::xs, ys -> loop (dot ys (x::zs) :: vs) xs ys (x::zs)
| [], _::(_::_ as ys) -> loop (dot ys zs :: vs) [] ys zs
| _ -> List.rev vs
loop [] xs ys []
convolve [2; 3; 1; 4] [4; 1; 2; 3]
Regarding the zeroes, how about e.g.
[for q in 0..l.Length-1 -> if q=i then l else 0]
(I haven't tested to verify that is exactly right, but hopefully the idea is clear.) In general, any use of # is a code smell.
Regarding overall performance, for small lists this is probably fine; for larger ones, you might consider using Seq rather than List for some of the intermediate computations, to avoid allocating as many temporary lists along the way.
It looks like maybe the final zip-then-map could be replaced by just a call to map2, something like
... fun r c -> (r,c) ||> List.map2 (+)
or possibly even just
... List.map2 (+)
but I'm away from a compiler so haven't double-checked it.
(fun ye -> x |> List.map ((*) ye))
Really ?
I'll admit |> is pretty, but you could just wrote :
(fun ye -> List.map ((*) ye) x)
Another thing that you could do is fuse the first two maps. l |> List.map f |> List.mapi g = l |> List.mapi (fun i x -> g i (f x)), so incorporating Tomas and Brian's suggestions, you can get something like:
let convolve y x =
let N = List.length x
y
|> List.mapi (fun i ye ->
[for _ in 1..i -> 0
yield! List.map ((*) ye) x
for _ in 1..(N-i-1) -> 0])
|> List.reduce (List.map2 (+))
I'm a bit stuck on the last step of getting the solution to problem 2 on Project Euler. This is the source I've gotten so far.
#light
module pe2 (* Project Euler Problem 2 solution *)
open System
let Phi = 1.6180339887;;
let invPhi = 1.0/Phi;;
let rootOfFive = 2.236067977;;
let maxFib = 4000000.0;
let Fib n =
System.Math.Round((Phi**n - invPhi**n)/rootOfFive);;
let FibIndices = Seq.unfold(fun i -> Some(i, i+3.0)) 3.0;;
let FibNos = FibIndices |> Seq.map(fun index -> Fib(index));;
let setAllowedFibNos = FibNos |> Seq.filter(fun fn -> (fn <= maxFib));;
// let answer = setAllowedFibNos |> Seq.fold (+) 0.0;
When I uncomment the last line, the process never seems to finish. So I was hoping that someone could give me a gentle nudge in the right direction. I did look at setAllowedFibNos and it looks right but it's also an infinite sequence so I only see the first three terms.
Also, could someone point me to the right way to chain the various sequences together? I tried something like this:
let answer = Seq.unfold(fun i-> Some(i, i + 3.0)) 3.0
|> Seq.map (fun index -> Fib(index))
|> Seq.filter(fun fn -> (fn <= maxFib))
|> Seq.fold (+) 0.0;;
But that didn't work. As you can probably guess I'm just learning F# so please go gentle and if this sort of question has been asked and answered before, please post a link to the answer and I'll withdraw this one.
let rec Fib(n) =
if (n < 2) then
1
else
Fib(n-2) + Fib(n-1)
Seq.initInfinite Fib
|> Seq.takeWhile (fun a -> a <= 4000000)
|> Seq.filter (fun a -> (a % 2) = 0)
|> Seq.fold (+) 0
'setAllowedFibNos' is indeed an infinite seq computation; 'fold' needs the whole sequence, so the 'filter' will run forever looking for another number <= maxFib.
Take a look at takeWhile:
http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/FSharp.Core/Microsoft.FSharp.Collections.Seq.html
I think it is what you want instead of filter.
Also note that you can use 'sqrt 5.0'.
I'm still trying to get used to the Seq approach. But, here is my solution without it.
#light
let rec fib n =
match n with
|0|1 -> n
|_ -> fib(n-1) + fib(n-2)
let maxFib = 4000000
let phi = (1.0 + sqrt(5.0)) / 2.0
let upperBound = 1 + int( log10((float(maxFib) - 0.5) * sqrt(5.0)) / log10(phi))
[1..upperBound] |> List.filter (fun x-> x%3=0) |> List.map fib |> List.filter (fun x -> x%2 = 0) |> List.filter (fun x -> x List.sum |> printfn "%d"
My solution is:
Seq.unfold (fun state ->
if (fst state + snd state > 4000000) then None
else Some(fst state + snd state, (snd state, fst state + snd state))) (0,1)
|> Seq.filter (fun x -> x % 2 = 0)
|> Seq.sum;;