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.
Related
I'm trying to do some mathematical operations with decimal options on a custom type:
type LineItem = {Cost: decimal option; Price: decimal option; Qty: decimal option}
let discount = 0.25M
let createItem (c, p, q) =
{Cost = c; Price = p; Qty = q}
let items =
[
(Some 1M , None , Some 1M)
(Some 3M , Some 2.0M , None)
(Some 5M , Some 3.0M , Some 5M)
(None , Some 1.0M , Some 2M)
(Some 11M , Some 2.0M , None)
]
|> List.map createItem
I can do some very simple arithmetic with
items
|> Seq.map (fun line -> line.Price
|> Option.map (fun x -> discount * x))
which gives me
val it : seq<decimal option> =
seq [null; Some 0.500M; Some 0.750M; Some 0.250M; ...]
If I try to actually calculate the thing I need
items
|> Seq.map (fun line -> line.Price
|> Option.map (fun x -> discount * x)
|> Option.map (fun x -> x - (line.Cost
|> Option.map (fun x -> x)))
|> Option.map (fun x -> x * (line.Qty
|> Option.map (fun x -> x))))
I get the error
error FS0001: Type constraint mismatch. The type
'a option
is not compatible with type
decimal
The type ''a option' is not compatible with the type 'decimal'
where I would have expected a seq<decimal option>.
I must be missing something but I can't seem to spot whatever it is I'm missing.
You are mixing decimal with decimal option.
If you're trying to solve everything with Option.map you may want to try with Option.bind instead, so your code will be 'linearly nested':
items
|> Seq.map (
fun line ->
Option.bind(fun price ->
Option.bind(fun cost ->
Option.bind(fun qty ->
Some ((discount * price - cost ) * qty)) line.Qty) line.Cost) line.Price)
which can be an interesting exercise, especially if you want to understand monads, then you will be able to use a computation expression, you can create your own or use one from a library like F#x or F#+:
open FSharpPlus.Builders
items |> Seq.map (fun line ->
monad {
let! price = line.Price
let! cost = line.Cost
let! qty = line.Qty
return ((discount * price - cost ) * qty)
}
)
but if you link F#+ you'll have Applicative Math Operators available:
open FSharpPlus.Operators.ApplicativeMath
items |> Seq.map (fun line -> ((discount *| line.Price) |-| line.Cost ) |*| line.Qty)
That's nice stuff to learn but otherwise I would suggest to use F# built-in features instead, like pattern-match, it would be easier:
items
|> Seq.map (fun line -> match line.Price, line.Qty, line.Cost with
| Some price, Some qty, Some cost ->
Some ((discount * price - cost ) * qty)
| _ -> None)
Then since you can also pattern-match over records it can be further reduced to:
items
|> Seq.map (function
| {Cost = Some cost; Price = Some price; Qty = Some qty} ->
Some ((discount * price - cost ) * qty)
| _ -> None)
Note that Option.map (fun x -> x) doesn't transform anything.
One problem you have is the following code:
(line.Cost |> Option.map (fun x -> x))
The lambda function (fun x -> x) already exists. This is the id function. It just returns whatever you have unchanged. You also could write the code you have like this:
(line.Cost |> Option.map id)
And the next thing. Mapping over the id function makes no sense. You unwrap whatever is inside the option, apply the id function to it. What didn't change the decimal at all. Then you wrap the decimal again in an option. You also can just write:
line.Cost
and completely remove the Option.map as it does nothing.
So the code you have here:
|> Option.map (fun x -> x - (line.Cost |> Option.map (fun x -> x)))
is identical to:
|> Option.map (fun x -> x - line.Cost)
This obviously does not work because here you try to subtract x a decimal with line.Cost a option decimal. So you get a type-error.
I guess what you really want to do is to subtract line.Cost from line.Price if line.Cost is present, otherwise you want to preserve line.Price unchanged.
One way would be just to provide a default value for line.Costs that can be used and have no effect on the subtraction. For example you could use the value 0 for subtraction if line.Costs is None.
So you also could write something like this instead:
|> Option.map (fun x -> x - (defaultArg line.Cost 0m))
A default value for multiplication would be 1m. So you overall end with.
items
|> Seq.map (fun line ->
line.Price
|> Option.map (fun x -> discount * x)
|> Option.map (fun x -> x - (defaultArg line.Cost 0m))
|> Option.map (fun x -> x * (defaultArg line.Qty 1m)))
The above code for example returns:
[None; Some -2.500M; Some -21.250M; Some 0.500M; Some -10.500M]
If your goal is that a whole computation turns into None as soon a single
value is None. I would just add map2 as a helper function.
module Option =
let map2 f x y =
match x,y with
| Some x, Some y -> Some (f x y)
| _ -> None
then you just can write:
items
|> List.map (fun line ->
line.Price
|> Option.map (fun price -> price * discount)
|> Option.map2 (fun cost price -> price - cost) line.Cost
|> Option.map2 (fun qty price -> price * qty) line.Qty)
and it will return:
[None; None; Some -21.250M; None; None]
Within the Option.map the x is actually a decimal, but the signature for Option.map is 'T option -> 'U option. So here:
Option.map (fun x -> x - (line.Cost |> Option.map (fun x -> x)))
you have the following:
Option.map (fun x -> /*decimal*/ x - /*decimal option*/(line.Cost |> Option.map (fun x -> x)))
So the decimal option has to be converted to decimal to be compatible with what's in the first Option.map. But now you have to deal with None result.
Below a quick (and nasty) fix that just is using an if statement to extract Value (which will be a decimal) or if None then return 0.
items
|> Seq.map (fun line -> line.Price
|> Option.map (fun x -> discount * x)
|> Option.map (fun x -> x - if line.Cost.IsSome then line.Cost.Value else 0m)
|> Option.map (fun x -> x * if line.Qty.IsSome then line.Qty.Value else 0m))
For a more sophisticated solution I recommend this answer.
For completeness sake, you may also leverage the monadic properties of the option type by "lifting" the values outside of the option. This is a somewhat simpler variant of the applicative approach linked by #PiotrWolkowski and those shown by #Gustavo. Applicatives not only wrap values in the monad, but also the functions applied to them.
We start by making the option type amenable to monadic operations in terms of bind and return. Thankfully, those functions are already defined, there's only a little tweak in the argument order.
let (>>=) ma f = Option.bind f ma
let ``return`` = Some
On top of this there's the lift function and a couple of operators for convenience. If needed, they could be generalized by marking them inline.
let liftOpt op x y =
x >>= fun a ->
y >>= fun b ->
``return`` (op a b)
let (.*) = liftOpt (*)
let (.-) = liftOpt (-)
Now your calculation becomes
items
|> Seq.map (fun line ->
(line.Price .* Some discount .- line.Cost) .* line.Qty )
|> Seq.iter (printfn "%A")
which will print
<null>
<null>
Some -21.250M
<null>
<null>
I know there's the back-pipe (<|) operator, referenced in several other SO answers. But that doesn't work well when combined with forward pipes (|>), which is common in chaining. However I'm looking for related options. Basically is there any built-in version of the below function definition? Or is this a bad/dangerous practice?
let inline (^%) f = f
let stuff =
[1;2;3]
|> Seq.filter ^% (>) 2
|> Seq.map ^% fun x -> x.ToString()
// compare to this, which doesn't compile (and would be hard to follow even if it did)
let stuff =
[1;2;3]
|> Seq.filter <| (>) 2
|> Seq.map <| fun x -> x.ToString()
There are some Haskell features, like optional infixing using backticks, and sections, which aren't available in F#. That makes certain constructs a bit more verbose.
Usually, I'd simply write a pipe of functions as the above like this:
let stuff =
[1;2;3]
|> Seq.filter (fun x -> x < 2)
|> Seq.map string
This is, in my opinion, much more readable. For example, using Seq.filter ^% (>) 2, I'd intuitively read that as meaning 'all values greater than 2', but that's not what it does:
> let inline (^%) f = f;;
val inline ( ^% ) : f:'a -> 'a
> let stuff =
[1;2;3]
|> Seq.filter ^% (>) 2
|> Seq.map ^% fun x -> x.ToString()
|> Seq.toList;;
val stuff : string list = ["1"]
If you leave the reader of the code in doubt of what the code does, you've just made everyone less productive. Using Seq.filter (fun x -> x < 2) may look more verbose, but is unambiguous to the reader.
I have the following variable:
data:seq<(DateTime*float)>
and I want to do something like the following F# code but using Deedle:
data
|> Seq.groupBy (fun (k,v) -> k.Year)
|> Seq.map (fun (k,v) ->
let vals = v |> Seq.pairwise
let first = seq { yield v |> Seq.head }
let diffs = vals |> Seq.map (fun ((t0,v0),(t1,v1)) -> (t1, v1 - v0))
(k, diffs |> Seq.append first))
|> Seq.collect snd
This works fine using F# sequences but I want to do it using Deedle series. I know I can do something like:
(data:Series<DateTime*float>) |> Series.groupBy (fun k v -> k.Year)...
But then I need to take the within group year diffs except for the head value which should just be the value itself and then flatten the results into on series...I am bit confused with the deedle syntax
Thanks!
I think the following might be doing what you need:
ts
|> Series.groupInto
(fun k _ -> k.Month)
(fun m s ->
let first = series [ fst s.KeyRange => s.[fst s.KeyRange]]
Series.merge first (Series.diff 1 s))
|> Series.values
|> Series.mergeAll
The groupInto function lets you specify a function that should be called on each of the groups
For each group, we create series with the differences using Series.diff and append a series with the first value at the beginning using Series.merge.
At the end, we get all the nested series & flatten them using Series.mergeAll.
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
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).