Type mismatch with pattern matching - f#

I have a code which works fine:
let rec calculate s l acc =
if length s = 0 then
acc
else
if first s = l then
calculate (rest s) l (acc+1)
else
calculate (rest s) (first s) acc
I want to rewrite it using pattern matching:
let rec calculate s l acc =
function
| _, _, _ when length s = 0 -> acc
| _, _, _ when first s = l -> calculate (rest s) l (acc+1)
| _, _, _ -> calculate (rest s) (first s) acc
But last function returns the error message:
| _, _, _ when first s = l -> calculate (rest s) l (acc+1) -----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/Users/demas/temporary/stdin(512,36): error FS0001: Type mismatch.
Expecting a
'a but given a
'b * 'c * 'd -> 'a The resulting type would be infinite when unifying ''a' and ''b * 'c * 'd -> 'a'
Why ?

Keyword function implies that the last (implicit) parameter of the function calculate should be tuple containing 3 elements because you are matching on _, _, _
You could rewrite it as:
let rec calculate s l acc =
match s, l, acc with
| _, _, _ when length s = 0 -> acc
| _, _, _ when first s = l -> calculate (rest s) l (acc+1)
| _, _, _ -> calculate (rest s) (first s) acc
Also you could make pattern matching more clear rewriting it like:
let rec calculate s l acc =
match (length s), (first s = l) with
| 0, _ -> acc
| _, true -> calculate (rest s) l (acc+1)
| _, _ -> calculate (rest s) (first s) acc

Related

Calling one-parameter function with two arguments?

I have this code:
type Sym = (string * float) list
let rec lookup v = function
| (v', k) :: vtab -> if v = v' then k else lookup v vtab
| (_ : Sym) -> failwith ("unbound: " + v)
To me, it looks like that lookup takes one argument v. But then we do lookup v vtab - now it seems like two arguments are being passed to lookup? How can this be valid when lookup only takes one argument?
It does take two parameters. The first one is v, the second one comes from function.
In F# function is syntactic sugar for match. More specifically, the word function means fun x -> match x with.
So you can read your code as:
let rec lookup v = fun x -> match x with
| (v', k) :: vtab -> if v = v' then k else lookup v vtab
| (_ : Sym) -> failwith ("unbound: " + v)
Which in turn is the same as:
let rec lookup v x = match x with
| (v', k) :: vtab -> if v = v' then k else lookup v vtab
| (_ : Sym) -> failwith ("unbound: " + v)

Is that a proper use of match with in F# or is there a more idiomatic way to accomplish the same

The code is getting a json string from a server and parses it into a jObject and then branches appropriately.
let j = JObject.Parse x
match x, j with
| _ when x = "pong" -> ()
| _ when j.ContainsKey "table" -> HandleTableMessages j x
| _ when j.ContainsKey "success" -> HandleSuccessMessages j
| _ when j.ContainsKey "error" -> HandleErrorMessages j
| _ when j.ContainsKey "info" -> j.SelectToken "info" |> string |> this.Print
| _, null -> this.Error ("malformed message: " + x)
| _ -> this.Error("unknown message type: " + x)
I think there is something a little bit heavy with the _ when part and I am wondering if there a better use of the F# grammar to express this?
It's a good sign that you realize this code is bad. It shows you may have better taste than most beginners. Using the simplest structure for a task is very important.
match x, j with
| _ when x = "pong" -> ()
...
First note that (x,j) is unused, so this simplifies to:
match () with
| _ when x = "pong" -> ()
...
Then you can realize that matching on a unit is silly, and that you should have used a simpler statement:
if x = "pong" then ()
elif j.ContainsKey "table" then HandleTableMessages j x
...
else this.Error("unknown message type: " + x)
I have just noticed that elif is not in the F# cheatsheet so I will try to get it added there as it's a basic keyword.
// Active Pattern
let (|Table|Success|Error|Info|Unknown|) (j: Newtonsoft.Json.Linq.JObject) =
if j.ContainsKey "table" then Table
elif j.ContainsKey "success" then Success
elif j.ContainsKey "error" then Error
elif j.ContainsKey "info" then Info
else Unknown
match x, j with
| "pong", _ -> ()
| _, Table -> HandleTableMessages j x
| _, Success -> HandleSuccessMessages j
| _, Error -> HandleErrorMessages j
| _, Info -> j.SelectToken "info" |> string |> this.Print
| _, null -> this.Error ("malformed message: " + x)
| _, Unknown
| _, _ -> this.Error("unknown message type: " + x)

Railway Oriented Programming and partial application

I like using ROP when I have to deal with IO/Parsing strings/...
However let's say that I have a function taking 2 parameters. How can you do clean/readable partial application when your 2 parameters are already a Result<'a,'b> (not necessary same 'a, 'b)?
For now, what I do is that I use tuple to pass parameters and use the function below to get a Result of a tuple so I can then bind my function with this "tuple-parameter".
/// Transform a tuple of Result in a Result of tuple
let tupleAllResult x =
match (fst x, snd x) with
| Result.Ok a, Result.Ok b -> (a,b) |> Result.Ok
| Result.Ok a, Result.Error b -> b |> Result.Error
| Result.Error a, _ -> a |> Result.Error
let f (a: 'T, b: 'U) = // something
(A, B) |> tupleAllResult
|> (Result.bind f)
Any good idea?
Here what I wrote, which works but might not be the most elegant
let resultFunc (f: Result<('a -> Result<'b, 'c>), 'd>) a =
match f with
| Result.Ok g -> (g a) |> Result.Ok |> Result.flatten
| Result.Error e -> e |> Result.Error |> Result.flatten
I am not seeing partial application in your example, a concept related to currying and argument passing -- that's why I am assuming that you are after the monadic apply, in that you want to transform a function wrapped as a Result value into a function that takes a Result and returns another Result.
let (.>>.) aR bR = // This is "tupleAllResult" under a different name
match aR, bR with
| Ok a, Ok b -> Ok(a, b)
| Error e, _ | _, Error e -> Error e
// val ( .>>. ) : aR:Result<'a,'b> -> bR:Result<'c,'b> -> Result<('a * 'c),'b>
let (<*>) fR xR = // This is another name for "apply"
(fR .>>. xR) |> Result.map (fun (f, x) -> f x)
// val ( <*> ) : fR:Result<('a -> 'b),'c> -> xR:Result<'a,'c> -> Result<'b,'c>
The difference to what you have in your question is map instead of bind in the last line.
Now you can start to lift functions into the Result world:
let lift2 f xR yR =
Ok f <*> xR <*> yR
// val lift2 :
// f:('a -> 'b -> 'c) -> xR:Result<'a,'d> -> yR:Result<'b,'d> -> Result<'c,'d>
let res : Result<_,unit> = lift2 (+) (Ok 1) (Ok 2)
// val res : Result<int,unit> = Ok 3

Develop a function that takes a list of integers that defines it the longest continuous chain of identical numbers

Please help.
Develop a function that takes a list of integers that defines it the longest continuous chain of identical numbers. The result of the function must be a pair (number, length of the chain)
my code:-
let findMaxSeq (nums: int list) =
let foldFun (curN, len, (curWinN, curWinLen)) n =
match len, curWinLen with
| 0, 0 -> (n, 1, (n,1))
| 0, _ -> (n, 1, (curWinN,curWinLen))
| _ when n = curN ->
let newLen = len+1
if (newLen>curWinLen) then (n, newLen, (n, newLen)) else (n, newLen, (curWinN, curWinLen))
| _ -> (n, 1, (curWinN, curWinLen))
let (_, _, (winner)) = nums |> List.fold foldFun (0, 0, (0, 0))
winner
but don't compile - in second let i have error:-
Block following this 'let' is unfinished. Expect an expression.
Could indentation be the problem? It compiles when formatted like this:
let findMaxSeq (nums: int list) =
let foldFun (curN, len, (curWinN, curWinLen)) n =
match len, curWinLen with
| 0, 0 -> (n, 1, (n,1))
| 0, _ -> (n, 1, (curWinN,curWinLen))
| _ when n = curN ->
let newLen = len+1
if (newLen>curWinLen) then (n, newLen, (n, newLen))
else (n, newLen, (curWinN, curWinLen))
| _ -> (n, 1, (curWinN, curWinLen))
let (_, _, (winner)) = nums |> List.fold foldFun (0, 0, (0, 0))
winner
This looked like a fun challenge, so I took a stab at it.
let findMaxRepeatedValue xs =
let rec loop (maxVal, maxCount) (curVal, curCount) = function
| [] -> if curCount > maxCount then (curVal, curCount) else (maxVal, maxCount)
| x::xs when x = curVal -> loop (maxVal, maxCount) (curVal, curCount + 1) xs
| x::xs ->
if curCount > maxCount then loop (curVal, curCount) (x, 1) xs
else loop (maxVal, maxCount) (x, 1) xs
match xs with
| [] -> invalidArg "xs" "empty list"
| [x] -> (x, 1)
| x::xs -> loop (x, 1) (x, 1) xs
Since your main question has been answered, here's yet another option/approach, for fun and profit :)
let longestChain nums =
let rec chain lst (num, cnt) = seq {
match lst with
| x :: xs -> if x = num then
yield! chain xs (num, cnt+1)
else
yield (num, cnt)
yield! chain xs (x, 1)
| [] -> yield (num, cnt)
}
match nums with
| x :: xs -> chain xs (x, 1) |> Seq.maxBy snd
| [] -> failwith "Cannot find the longest chain in an empty list"
As Daniel pointed out, this was just an indentation problem - F# is an indentation sensitive language (spaces have meaning) and so you need to indent nested blocks further. Your function works just fine when it is indented correctly!
let findMaxSeq (nums: int list) =
let foldFun (curN, len, (curWinN, curWinLen)) n =
match len, curWinLen with
| 0, 0 -> (n, 1, (n,1))
| 0, _ -> (n, 1, (curWinN,curWinLen))
| _ when n = curN ->
let newLen = len+1
if (newLen>curWinLen) then
(n, newLen, (n, newLen))
else
(n, newLen, (curWinN, curWinLen))
| _ -> (n, 1, (curWinN, curWinLen))
let (_, _, (winner)) = nums |> List.fold foldFun (0, 0, (0, 0))
winner
findMaxSeq [1;2;2;2;3;3;1;1;1;1;1;4;4]
Note that:
the body of function foldFun is indented further than the let that defines the function.
the body of the complex pattern (matching when n=curN) is also indented further
I also split if then to multiple lines (for readability - this is not required)
Daniel's solution is perfectly fine too - but since you asked about a version based on List.fold, I thought I'd answer with a corrected version of your original code.
As an aside, if you wanted to do more operations like this on some actual data (like time series) rather than just solve this for the purpose of learning F#, then Deedle which is a library for working with series data has a nice abstraction called chunkWhile that splits series into chunks while some condition holds (e.g. while the values are the same) and makes it pretty easy to write this:
#r "lib/Deedle.dll"
open Deedle
let findMaxSeq values =
let s = Series.ofValues values
s |> Series.chunkWhile (fun k1 k2 -> s.[k1] = s.[k2])
|> Series.map(fun k chunk -> s.[k], Series.countKeys chunk)
|> Series.values
|> Seq.maxBy snd
findMaxSeq [1;2;2;2;3;3;1;1;1;1;1;4;4]
Here's an attempt which is generic and uses standard library functions. Since you didn't say what the answer should be when the input sequence is empty, I'm not returning a pair of number * length directly, but wrap that up in an option.
let inline findMaxSeq xs =
xs
|> Seq.scan (fun state x ->
match state with
| Some (y, i) when x = y -> Some (x, i + 1)
| _ -> Some (x, 1) )
None
|> Seq.maxBy (function
| Some (_, i) -> i
| _ -> 0 )
findMaxSeq [1;2;2;2;3;3;1;1;1;1;1;4;4] // Some (1, 5)
findMaxSeq Seq.empty<int> // None
Sorry, but most F# code I've seen her so far looks to me like C# in disguise. I am sure functional F# programmers can do better, along the lines of this Haskell solution:
maxrv = maximumBy (comparing fst) . map (\xs -> (length xs, xs)) . group

How to create a "Pair" function to match against a string list?

I was doing an exercise on F# Wiki Book on List (scroll to the bottom) to create a Pair method.
I was able to pair a integer list without problem but an F# exception was thrown for a string list. It is just too cryptic for me to decipher what the exception means for an F# beginner like me.
Here is my initial attempt to implementing Pair on fsi.exe
> let pair l =
- let rec loop acc = function
- | [] -> acc
- | (hd1 :: hd2 :: tl) -> loop ((hd1, hd2) :: acc) tl
- List.rev(loop [] l)
-
- printfn "%A" ([1..10] |> pair)
- printfn "%A" ([ "one"; "two"; "three"; "four"; "five" ] |> pair);;
let rec loop acc = function
-----------------------^
stdin(2,24): warning FS0025: Incomplete pattern matches on this expression.
For example, the value '[_]' will not be matched
val pair : 'a list -> ('a * 'a) list
[(1, 2); (3, 4); (5, 6); (7, 8); (9, 10)]
Microsoft.FSharp.Core.MatchFailureException:
Exception of type 'Microsoft.FSharp.Core.MatchFailureException' was thrown.
at FSI_0002.clo#2T.Invoke(List`1 acc, List`1 _arg1)
at FSI_0002.pair[T](List`1 l)
at <StartupCode$FSI_0002>.$FSI_0002._main()
stopped due to error
So Pair does work on integer version
and the function signature
val pair : 'a list -> ('a * 'a) list
indicates that Pair operates on a generic list.
Question: Then why would Pair not work on a string list?
[ANSWER] (my version)
Simply returning accumulated list for else case (_) did the trick.
And the warning is taken care of, as well.
let pair l =
let rec loop acc = function
// | [] -> acc
| (hd1 :: hd2 :: tl) -> loop ((hd1, hd2) :: acc) tl
| _ -> acc
List.rev(loop [] l)
printfn "%A" ([1..10] |> pair)
printfn "%A" ([ "one"; "two"; "three"; "four"; "five" ] |> pair)
[EDIT2] Well, I will also post my version of Unpair for completeness.
let unpair l = [for (a,b) in l do yield! a :: b :: []]
Here is somewhat flawed benchmarking using solution version against that of mine for 1 million item lists
#light
open System;
let pn l = printfn "%A" l
let duration f =
let startTime = DateTime.Now;
let returnValue = f()
let endTime = DateTime.Now;
printfn "Duration (ms): %f" (endTime - startTime).TotalMilliseconds
returnValue
let ll = [for a in 1..1000000 do yield (a)]
let tl = [for a in 1..1000000 do yield (a,a)]
let pair1 l =
let rec loop acc = function
| [] | [_] -> List.rev acc
| h1 :: h2 :: tl -> loop ((h1, h2) :: acc) tl
loop [] l
let unpair1 l =
let rec loop acc = function
| [] -> List.rev acc
| (h1, h2) :: tl -> loop (h2 :: h1 :: acc) tl
loop [] l
let pair2 l =
let rec loop acc = function
| (hd1 :: hd2 :: tl) -> loop ((hd1, hd2) :: acc) tl
| _ | [_] -> acc
List.rev(loop [] l)
let unpair2 l = [for (a,b) in l do yield! a :: b :: []]
pn(duration (fun() -> ll |> pair1))
pn(duration (fun() -> tl |> unpair1))
pn(duration (fun() -> ll |> pair2))
pn(duration (fun() -> tl |> unpair2))
Benchmark Result:
Solution version
PAIR -> Duration (ms): 255.000000
UNPAIR -> Duration (ms): 840.000000
My version
PAIR -> Duration (ms): 220.000000
UNPAIR -> Duration (ms): 1624.000000
I don't think your version of Pair would work on a list of an odd number of anything. You happen to test an even number of ints and a odd number of strings. I think your second argument to match implies a list of at least two members. So you break off 2 break off 2 and get to a list with 1 element and none of your conditions match.
[_] is a 1 item list with anything in it. You must provide a predicate that matches it.

Resources