F# Is this a bug in Option.map - f#

Given the following code:
let mapOption (f : ('a -> 'b)) (x : 'a option) =
match x with
| Some x -> Some(f(x))
| None -> None
let mapOptions (f : ('a -> 'b)) (xs : 'a option list) : 'b option list =
xs
|> List.map (fun (x : 'a option) -> mapOption f x)
let myList = [None; Some 1; Some 2; None]
let a = myList |> mapOptions (fun x -> x + 2)
let b = myList |> List.map(fun x-> x |> Option.map(fun y -> y + 2))
Why is the result for a and b equal to :
[null; Some 3; Some 4; null] or val it : int option list = [null; Some 3; Some 4; null]
Should it not be:
[None; Some 3; Some 4; None]

None is represented by null in the CLR. You can see that by experimenting with FSI:
> [Some 3; None];;
val it : int option list = [Some 3; null]
It still works, though::
> [Some 3; None] |> List.choose id;;
val it : int list = [3]
So [null; Some 3; Some 4; null] is the same as [None; Some 3; Some 4; None]:
> a = [None; Some 3; Some 4; None];;
val it : bool = true
where a is the value from the OP.

Related

How to allow a function to accept a generic list of functions?

How to allow a function to accept a generic list of functions?
I have the code below, but the compiler is rejecting the line where I try to set partiallyAppliedAdds, with the error:
Type mismatch. Expecting a int -> int' given a int -> 'a -> 'b'
type ApplicativeFunctor(fnList: 'a list) =
member private this.fnList: 'a list = fnList
member this.ap (apTarget: int list) = ([], this.fnList) ||> List.fold (fun (acc: 'a list) fn -> acc # (apTarget |> List.map fn))
let add1 a = a + 1
ApplicativeFunctor([add1]).ap([1]) // [2]
let arg1 = [1; 3]
let add x = fun y -> x + y
let partiallyAppliedAdds = ApplicativeFunctor[add].ap(arg1) // Type mismatch. Expecting a int -> int' given a int -> 'a -> 'b'
Is this easily accomplishable in F#, or should I approach this differently?
To fix your version, you do:
type ApplicativeFunctor<'a,'b>(fnList: list<'a -> 'b>) =
member private _.fnList = fnList
member this.ap apTarget =
([], this.fnList)
||> List.fold (fun acc fn -> acc # List.map fn apTarget)
let add1 a = a + 1
let res1 = ApplicativeFunctor([add1]).ap([1]) (* [2] *)
printfn "%A" res1
let paAdd = ApplicativeFunctor[fun x y -> x + y].ap([1;3])
printfn "%A" paAdd
But the general approach is just
let ap fs xs =
List.foldBack2 (fun f x state ->
f x :: state
) fs xs []
let add x y z = x + y + z
let xs = [1..3]
let ys = [10;20;30]
let zs = [100;200;300]
let res1 = (ap (ap (List.map add xs) ys) zs)
printfn "%A" res1 (* [111;222;333] *)
(* Custom operators *)
let (<!>) = List.map
let (<*>) = ap
let res2 = add <!> xs <*> ys <*> zs
printfn "%A" res2 (* [111;222;333] *)

How to sum adjacent numbers of same sign using List.fold in F#

Let's say I have a list in F# like this: [5,-2, -6, 7, -2, 2, 14, 2]
I want to write a function that will use List.fold to return a new list such as [5, -8, 7, -2, 18]
My template looks like this:
let sumAdjacentOfSameSign (lst :int list) : int list =
let f x y =
if x.Length = 0 then
[y]
elif System.Math.Sign(x) = System.Math.Sign(y) then ...
else y :: x
List.fold f [] lst
I need to fill in the ... part but can't quite say how.
Making the fewest changes to your code, I would do this:
let sumAdjacentOfSameSign (lst :int list) : int list =
let f (x : int list) (y : int) =
if x.Length = 0 then
[y]
elif System.Math.Sign(x.Head) = System.Math.Sign(y) then
(x.Head + y) :: x.Tail
else y :: x
List.fold f [] lst
|> List.rev // note that you have to reverse the resulting list
But I would suggest simplifying f to:
let f (x : int list) (y : int) =
match x with
| head :: tail when
System.Math.Sign(head) = System.Math.Sign(y) ->
(head + y) :: tail
| _ -> y :: x

Replicate list items n times in a F# sequence

I have a sequence in F#:
let n = 2
let seq1 = {
yield "a"
yield "b"
yield "c"
}
I want to print every item in the sequence n times. I can do it this way:
let printx line t =
for i = 1 to t do
printfn "%s" line
seq1 |> Seq.iter (fun i -> printx i n)
Output of this is:
a
a
b
b
c
c
I think this is not the best solution. How to replicate the items in the sequence?
You can create a function to replicate each element of an input sequence:
let replicateAll n s = s |> Seq.collect (fun e -> Seq.init n (fun _ -> e))
then
seq1 |> replicateAll 2 |> Seq.iter (printfn "%s")
I would rather go with a sequence computation expression.
Looks cleaner:
let replicateAll n xs = seq {
for x in xs do
for _ in 1..n do
yield x
}
There is actually a replicate function:
let xs = [1; 2; 3; 4; 5]
xs |> List.collect (fun x -> List.replicate 3 x)
//val it : int list = [1; 1; 1; 2; 2; 2; 3; 3; 3; 4; 4; 4; 5; 5; 5]
And you can do function composition on it, which will get rid of the lambda:
let repCol n xs = (List.replicate >> List.collect) n xs

Folding list of options

Given a list [Some 1; Some 2; Some 3] I would like an output Some 6 . Given a list [Some 1; None] should yield None.
But I'm finding it a bit more difficult than I had imagined to achieve this in a clean way.
The best I could come up with was this
let someNums = [Some 1; Some 2; Some 3]
someNums
|> List.reduce (fun st v ->
Option.bind (fun x ->
Option.map (fun y -> x + y) st) v )
let lift op a b =
match a, b with
| Some av, Some bv -> Some(op av bv)
| _, _ -> None
let plus = lift (+)
[Some 1; Some 2; Some 3]
|> List.reduce plus
// val it : int option = Some 6
[Some 1; None]
|> List.reduce plus
// val it : int option = None
with fold
[Some 1; None]
|> List.fold plus (Some 0)
// val it : int option = None
[Some 1; Some 2; Some 3]
|> List.fold plus (Some 0)
// val it : int option = Some 6
[Some 1; None; Some 2]
|> List.fold plus (Some 0)
// val it : int option = None
You can accomplish this by defining a map2 function for option values:
let optionMap2 f x y =
match x, y with
| (Some x', Some y') -> Some (f x' y')
| _ -> None
This would enable you to write the function you want:
let sumSome = List.fold (optionMap2 (+)) (Some 0)
Example:
> [Some 1; Some 2; Some 3] |> sumSome;;
val it : int option = Some 6
> [Some 1; None; Some 3] |> sumSome;;
val it : int option = None
At the moment, the optionMap2 function isn't available in the F# core library, but probably will be part of the Option module in the future.
Here is an naive implementation of the sequence Gustavo talked about:
let rec sequence =
function
| [] -> Some []
| (Some o :: os) ->
sequence os
|> Option.map (fun os' -> o::os')
| _ -> None
(please note that this is not tail-recursive and not optimized at all so you should transform it if you gonna need it for large lists)
Which would work just as Gustavo told you:
> sequence [Some 1; Some 2; Some 2] |> Option.map List.sum;;
val it : int option = Some 5
> sequence [Some 1; None; Some 2] |> Option.map List.sum;;
val it : int option = None

Time complexity O() of two two part functions

What would the time complexity be of these two algorithms?
let rec fol f a = function
| [] -> a
| x::xs -> fol f (f a x) xs;;
let mergelist xs = List.fol (#) [] xs
and
let rec folB f xs a =
match xs with
| [] -> a
| y::ys -> f y (folB f ys a);;
let mergelist2 xs = List.folB (#) xs []
and how would i be able to test it my self?
Should return something like
mergelist [[1;2];[];[3];[4;5;6]];;
val it : int list = [1; 2; 3; 4; 5; 6]
Here is a quick&dirty snippet of how you can compare the two operations with n lists of length 3 each:
let rec fol f a = function
| [] -> a
| x::xs -> fol f (f a x) xs;;
let rec folB f xs a =
match xs with
| [] -> a
| y::ys -> f y (folB f ys a);;
let compareThemFor n =
let testList = List.replicate n [1;2;3]
let count = ref 0
let myCons x xs =
incr count
x :: xs
let myApp ys =
List.foldBack myCons ys
let mergelist = fol myApp []
mergelist testList |> ignore
let countA = !count
count := 0
let mergelist2 xs = folB myApp xs []
mergelist2 testList |> ignore
let countB = !count
(countA, countB)
and this is what you will get:
> compareThemFor 2;;
val it : int * int = (3, 6)
> compareThemFor 3;;
val it : int * int = (9, 9)
> compareThemFor 4;;
val it : int * int = (18, 12)
> compareThemFor 5;;
val it : int * int = (30, 15)
> compareThemFor 6;;
val it : int * int = (45, 18)
as you can see the second is far better and I hope the comments above helps you understand why.
Just in case here is the n=3 version for mergelist:
mergelist [[1;2;3];[3;4;5];[6;7;8]]
{ second case in `fol` with `x=[1;2;3]` and `xs=[[3;4;5];[6;7;8]]` }
= fol (#) ([] # [1;2;3]) [[3;4;5];[6;7;8]] // one # of 0 elements = 0 operations
{ second case in `fol` with `x=[3;4;5]` and `xs=[[6;7;8]]` }
= fol (#) ([1;2;3] # [3;4;5]) [[6;7;8]] // one # of 3 elements = 3 operations
{ second case in `fol` with `x=[6;7;8]` and `xs=[]` }
= fol (#) ([1;2;3;3;4;5] # [6;7;8]) [] // one # of 6 elements = 6 operations
{ first case }
= [1;2;3;3;4;5;6;7;8] // 0+3+(3+3)=9 Operations Total
please note that you prepend [1,2,3] multiple times ...

Resources