Trouble concatenating results of a function - f#

My professor is having us implement Cartesian products in F#. He is providing a type for us to use:
type SET =
| I of int list // I [1;2;3]
| S of string list // S ["a";"b";"c"]
| IS of (int * string) list // IS [(1, "a");(2, "b")]
| II of (int * int) list // II [(1,2); (3,4); (5,6)]
| SS of (string * string) list // SS [("a","b"); ("c","d")]
| SI of (string * int) list // SI [("a", 1); ("b", 2); ("c", 3)]
| SISI of ((string * int) * (string * int)) list // SISI [(("a", 1), ("b", 2)); (("c", 3), "d", 4))]
| SIIS of ((string * int) * (int * string)) list // SIIS [(("a", 1), (2, "b")); (("c", 3), (4, "d"))]
In doing so, we are also given a 'product' function which behaves as follows:
let product s1 s2 =
match (s1, s2) with
| (I s1, I s2) -> II (pairs s1 s2)
| (S s1, S s2) -> SS (pairs s1 s2)
| (I s1, S s2) -> IS (pairs s1 s2)
| (S s1, I s2) -> SI (pairs s1 s2)
| (SI s1, IS s2) -> SIIS (pairs s1 s2)
| (SI s1, SI s2) -> SISI (pairs s1 s2)
The assignment is to create a function, 'pairs', that assembles the Cartesian product of the SET elements. We were told to begin with creating a function that can distribute a value across a list. I have done so here:
let rec dist a L =
match L with
| [] -> []
| h::t -> (a,h) :: dist a t
So far, my function looks like this:
let rec pairs s1 s2 =
match s1 with
| [] -> []
| h::t -> dist h s2 // AND (pairs t s2)
I don't understand how I need to amend the last line of the match statement to properly reflect the output we desire. This will complete part of the function successfully, but only the first bit (relevant to the fact that the list head is being distributed, but not the tail). How can I concatenate the results of this function's first loop on the s1's head to 'pairs t s2' so that the elements created in the first segment will match the second in a way that prevents the expected types from clashing?

Sorry, this was a really stupid question. In case a similar case can be helped by anyone, this situation can be resolved by writing the last line as:
let rec pairs s1 s2 =
match s1 with
| [] -> []
| h::t -> (dist h s2) # (pairs t s2)
I had previously tried all my concatenation with the :: operator, however this is the wrong type of operator for this operation.

Related

recursive tuples in F# [duplicate]

Directly using recursion, write a function truesAndLength : bool list -> int * int that
returns both the length of the list (in the first component of the pair), and the number of
elements of the list that are true (in the second component). Your function must only iterate
over the elements of the list once. (Do not use any of the functions from the List module.)
this is my code so far:
let rec length bs =
match bs with
| [] -> 0
| b::bs -> 1 + length bs
let rec trues bs =
match bs with
| [] -> 0
| b::bs -> if b = true then 1 + trues bs else trues bs
let truesandlength bs =
let l = length bs
let t = trues bs
(l, t)
truesandlength [true; true; false]
This works by im iterating through the list 2 times, i can't figure out how to iterate only 1. Any tips?
Based on your comments, here's how I suggest you think about the b::bs case:
Call truesAndLengths recursively on the tail of the list. This gives you tTail (the # of trues) and lTail (the length) of the tail.
Compute t and l for the full list based on the value of b. (E.g. l is one more than lTail.)
Return t, l.
The key is to call truesAndLengths recursively in only one place in your code, passing it the tail of the list.
let rec truesAndLength bs =
let sum a b = (fst a + fst b, snd a + snd b)
match bs with
| [] -> 0, 0
| head::tail ->
if head then sum (1,1) (truesAndLength tail) else sum (1, 0) (truesAndLength tail)

F# type test pattern matching: decomposing tuple objects

Just curious why I can't do this:
let myFn (data : obj) =
match data with
| :? (string * string) as (s1, s2) -> sprintf "(%s, %s)" s1 s2 |> Some
| :? (string * string * int) as (s1, s2, i) -> sprintf "(%s, %s, %d)" s1 s2 i |> Some
| _ -> None
How come?
See F# spec, section 7.3 "As patterns"
An as pattern is of the form pat as ident
Which means you need to use an identifier after as:
let myFn (data : obj) =
match data with
| :? (string * string) as s1s2 -> let (s1, s2) = s1s2 in sprintf "(%s, %s)" s1 s2 |> Some
| :? (string * string * int) as s1s2i -> let (s1, s2, i) = s1s2i in sprintf "(%s, %s, %i)" s1 s2 i |> Some
| _ -> None

How to use match Map elements in F#?

I tried to create a function that takes two integers a,b as input and return 5 if a=1 b=2 and 6 otherwise, Here is what I did:
let examplef (a:int), (b:int)=
match a,b with
|1,2 -> 5
|_,_->6;;
It gives this error: "The pattern discriminator 'examplef' is not defined."
I ask this question because of the error in this code:
type Team = string
type Goals = Goals of int
type Points = Points of int
type Fixture = Team * Team
type Result = (Team * Goals) * (Team * Goals)
type Table = Map<Team,Points>
let league =["Chelsea"; "Spurs"; "Liverpool"; "ManCity"; "ManUnited"; "Arsenal"; "Everton"; "Leicester"]
let pointsMade (a: Result)=
match a with
|((b,Goals bg),(c,Goals cg))-> if b<c then ((b,Points 0),(c, Points 3))
elif b=c then ((b,Points 1),(c,Points 1))
else ((b, Points 3),(c, Points 0))
I get an error when trying to define the following function:
let updateTable (t:Table, r: Result)=
let pointmade = pointsMade r
match pointmade with
|((f,Points s),(f1,Points s1))-> match Map.tryFind f t Map.tryFind f1 t with
|None, None -> t
|Some Points x, Some Points y ->t .Add (f, Points s+x1) .Add(f1, Points s1+y1)
When I hover the mouse over the first "Map.tryFind f t" It says "This value is not a function and cannot be applied. Also, there is an error with t .Add (f, Points s+x1) .Add(f1, Points s1+y1) it says: "Successive arguments should be separated by space and tuples and arguments involving functions or method applications should be parenthesized".
Please help
It looks like you're confusing tuple and curried arguments.
Examples with a single tuple argument (parenthesis are requiered).
signature: int * int -> int
//let example1 (a: int, b:int) =
let example1 (a, b) =
match a, b with
| 1, 2 -> 5
| _ -> 6
//let example2 (t: int * int) =
let example2 t =
match t with
| 1, 2 -> 5
| _ -> 6
Example with two curried arguments:
signature: int-> int -> int
//let example3 (a: int) (b: int) =
let example3 a b =
match a, b with
| 1, 2 -> 5
| _ -> 6
Anyway, The code that work looks like this:
open System.Security.Cryptography
open System.Threading
type Team = string
type Goals = Goals of int
type Points = Points of int
type Fixture = Team * Team
type Result = (Team * Goals) * (Team * Goals)
type Table = Map<Team,Points>
let league =["Chelsea"; "Spurs"; "Liverpool"; "ManCity"; "ManUnited"; "Arsenal"; "Everton"; "Leicester"]
let pointsMade (a: Result)=
match a with
|((b,Goals bg),(c,Goals cg))-> if bg<cg then ((b,Points 0),(c, Points 3))
elif bg=cg then ((b,Points 1),(c,Points 1))
else ((b, Points 3),(c, Points 0))
let initEntry (name:Team)=(name, Points 0)
let initializeTable l = Map.ofList (List.map initEntry l)
let updateTable (t:Table, r: Result)=
let pointmade = pointsMade r
match pointmade with
|((f,Points s),(f1,Points s1))-> match Map.tryFind f t, Map.tryFind f1 t with
|None, None -> t
|Some x, Some y-> match x,y with
| Points x1 , Points y1 -> t |> Map.add f (Points(x1+s)) |> Map.add f1 (Points (y1+s1))
|None, Some y -> match y with
| Points y1 -> t.Add(f,Points s) .Add(f1, Points (s1+y1))
|Some x, None -> match x with
| Points x1 -> t.Add(f,Points (s+x1)) .Add(f1, Points s1)
let rec weekendUpdate (t:Table , rl:Result list)=
match rl with
|[]->t
|ai::at-> weekendUpdate(updateTable(t,ai),at)
let rec seasonUpdate (t:Table, sll: Result list list)=
match sll with
|[]->t
|ah::at-> seasonUpdate(weekendUpdate(t,ah),at)
let less((s1,n1):Team * Points, (s2,n2):Team * Points) =
match n1,n2 with
|Points m1,Points m2 ->if m1<m2 then true
else false
let rec myinsert item lst =
match lst with
| [] -> [item]
| x::xs -> if less(item,x) then x::(myinsert item xs) else item::lst
let rec isort lst =
match lst with
| [] -> []
| x::xs -> myinsert x (isort xs)
let showStandings (t:Table) = isort (Map.toList t)
In your "working code", in the pointsMade function you do not need to use pattern matching, you can simply use a let binding.
let pointsMade (r: Result) =
let (t1, Goals g1), (t2, Goals g2) = r
if g1 < g2 then (t1, Points 0), (t2, Points 3)
elif g1 = g2 then (t1, Points 1), (t2, Points 1)
else (t1, Points 3), (t2, Points 0)
The updateTable function also can be re-written in more concise way by using some addPoints function to avoid repeating the same thing for each team.
let addPoints (team: Team, Points points) (table: Table) =
match Map.tryFind team table with
| None -> table
| Some (Points p) -> Map.add team (Points (points + p)) table
let updateTable (table: Table, result: Result) =
let pts1, pts2 = pointsMade result
table |> addPoints pts1 |> addPoints pts2

F#: grouping by recurring sequences of elements

I have a sequence of pairs (key, value) like
[("a", 1), ("a", 2), ("a", 111), ("b", 3), ("bb", 1), ("bb", -1), ...]
, what is the most effective way to convert it into sequence like
[("a", [1,2,111]), ("b", [3]), ("bb", [1,-1])]
or similar?
The sequence has following property: it's really big (>2Gb)
This makes Seq.groupBy really ineffective and incorrect, are there any other ways to do it?
P.S.: this sequence:
[("a", 1), ("a", 2), ("a", 111), ("bb", 1), ("bb", -1), ("a", 5), ("a", 6), ...]
should be converted as
[("a", [1,2,111]), ("bb", [1,-1]), ("a", [5,6]), ...]
--
edit #1: Fixed incorrect sample
edit #2: Sequence is big, so lazy (or fastest) solution is preferred
If you want the option to get lazy results, then I don't think there's an elegant way without maintaining mutable state. Here's a relatively straight-forward one with mutation. You maintain a store of the last key you saw, and all the values that correspond to that:
let s = [("a", 1); ("a", 2); ("a", 111); ("bb", 1); ("bb", -1); ("a", 5); ("a", 6)]
let s2 =
[
let mutable prevKey = None
let mutable values = System.Collections.Generic.List<_>()
let init key value =
prevKey <- Some key
values.Clear()
values.Add value
for (key, value) in s do
match prevKey with
| None -> init key value
| Some k when k = key -> values.Add value
| Some k ->
yield (k, List.ofSeq values)
init key value
match prevKey with
| Some k -> yield (k, List.ofSeq values)
| _ -> ()
]
This gives:
val s2 : (string * int list) list =
[("a", [1; 2; 111]); ("bb", [1; -1]); ("a", [5; 6])]
For lazy evaluation, replace the [ ... ] with seq { ... }
A simple recursive approach with no mutable state.
let rec chunk inseq (accumelem,accumlist) =
match inseq with
|(a,b)::c ->
match accumelem with
|Some(t) -> if t=a then chunk c (accumelem,b::accumlist) else (t,accumlist)::(chunk c (Some(a),b::[]))
|None -> chunk c (Some a,b::[])
|[] ->
match accumelem with
|Some(t) -> (t,accumlist)::[]
|None -> []
chunk [("a", 1); ("a", 2); ("a", 111); ("bb", 1); ("bb", -1); ("a", 5);("a", 6)] (None,[])
val it : (string * int list) list =
[("a", [111; 2; 1]); ("bb", [-1; 1]); ("a", [6; 5])]
Here is a recursive solution:
let test = [("a", 1); ("a", 2); ("a", 111); ("bb", 1); ("bb", -1); ("a", 5); ("a", 6)]
let groupByAdjacentElements alist =
let rec group a groupAcc prevElement adjacentAcc =
match a with
| [] -> match adjacentAcc with
| [] -> groupAcc
| _ -> (prevElement, List.rev adjacentAcc)::groupAcc
| (b, c)::tail -> if b = prevElement then
group tail groupAcc prevElement (c::adjacentAcc)
else
group tail ((prevElement, List.rev adjacentAcc)::groupAcc) b [c]
group alist [] (fst alist.Head) []
|> List.rev
let b = groupByAdjacentElements test
It returns: [("a", [1; 2; 111]); ("bb", [1; -1]); ("a", [5; 6])]
If you want lazy evaluation, you should consider trying LazyList
EDIT: Here's a script comparing LazyList from ExtCore to the accepted solution. It generates a large text file and then does the transformations asked for. Note that the LazyList is returned in reverse order:
open System.Diagnostics
open System.IO
open ExtCore
let fileName = "Test.txt"
let outFile = new StreamWriter(fileName)
for i in [1..20000*300] do
outFile.WriteLine("a,1")
outFile.WriteLine("a,2")
outFile.WriteLine("a,111")
outFile.WriteLine("bb,1")
outFile.WriteLine("bb,-1")
outFile.WriteLine("a,5")
outFile.WriteLine("a,6")
outFile.WriteLine("c,8")
outFile.Close()
printfn "Finished Writing to File"
let data = System.IO.File.ReadLines(fileName)
|> Seq.map (fun i -> let parts = i.Split(',')
(parts.[0], parts.[1]))
printfn "Finished Reading File"
let s2 data =
[
let mutable prevKey = None
let mutable values = System.Collections.Generic.List<_>()
let init key value =
prevKey <- Some key
values.Clear()
values.Add value
for (key, value) in data do
match prevKey with
| None -> init key value
| Some k when k = key -> values.Add value
| Some k ->
yield (k, List.ofSeq values)
init key value
match prevKey with
| Some key -> yield (key, List.ofSeq values)
| _ -> ()
]
let groupByAdjacentElements aseq =
let alist = LazyList.ofSeq aseq
let rec group alist groupAcc prevElement adjacentAcc =
match alist with
| Cons((b, c), tail) ->
if b = prevElement then
group tail groupAcc prevElement (c::adjacentAcc)
else
group tail (LazyList.consDelayed (prevElement, List.rev adjacentAcc) (fun () -> groupAcc)) b [c]
| Nil ->
match adjacentAcc with
| [] -> groupAcc
| _ -> LazyList.consDelayed (prevElement, List.rev adjacentAcc) (fun () -> groupAcc)
group alist LazyList.empty (fst (alist.Head())) []
let groupByAdjacentElementsList aseq =
let alist = aseq |> Seq.toList
let rec group a groupAcc prevElement adjacentAcc =
match a with
| [] -> match adjacentAcc with
| [] -> groupAcc
| _ -> (prevElement, List.rev adjacentAcc)::groupAcc
| (b, c)::tail -> if b = prevElement then
group tail groupAcc prevElement (c::adjacentAcc)
else
group tail ((prevElement, List.rev adjacentAcc)::groupAcc) b [c]
group alist [] (fst alist.Head) []
|> List.rev
[<EntryPoint>]
let main argv =
let stopwatch = new Stopwatch()
stopwatch.Start()
let b = s2 data
printfn "The result is: %A" b
stopwatch.Stop()
printfn "It took %A ms." stopwatch.ElapsedMilliseconds
System.GC.WaitForFullGCComplete() |> ignore
stopwatch.Reset()
stopwatch.Start()
let b = groupByAdjacentElements data
printfn "The result is: %A" b
stopwatch.Stop()
printfn "It took %A ms." stopwatch.ElapsedMilliseconds
System.GC.WaitForFullGCComplete() |> ignore
stopwatch.Reset()
stopwatch.Start()
let b = groupByAdjacentElementsList data
printfn "The result is: %A" b
stopwatch.Stop()
printfn "It took %A ms." stopwatch.ElapsedMilliseconds
0
I when using files of around 300MB in size, LazyList was slightly slower (83s to 94s) than the seq solution. That said LazyList has the major advantage that iterating over it is cached, unlike the sequence solution. The normal list solution was faster than both even when doing List.rev (without it was around 73s).
Grouping by adjacent keys can be also done without mutable bindings. With Seq.scan, it's possible to generate a lazy sequence with eager chunk. It already provides for one of the special cases, the first element of the sequence; by wrapping the input sequence as options followed by None we can take care of the other. Afterwards, we skip over intermediate results and strip out the state with Seq.choose.
For maximum versatility, I'd like to suggest a signature similar to Seq.groupBy,
f:('T -> 'Key) -> xs:seq<'T> -> seq<'Key * 'T list> when 'Key : equality
which takes a key projection function as first argument.
let chunkBy (f : 'T-> 'Key) xs =
// Determine key and wrap in option
seq{for x in xs -> Some(f x, x)
// Indicates end of sequence
yield None }
|> Seq.scan (fun (_, acc, previous) current ->
match previous, current with
| Some(pKey, _), Some(key, value) when pKey = key ->
// No intermediate result, but add to accumulator
None, value::acc, current
| _ ->
// New state is 3-tuple of previous key and completed chunk,
// accumulator from current element, and new previous element
Option.map (fun (k, _) -> k, List.rev acc) previous,
Option.map snd current |> Option.toList, current )
(None, [], None)
|> Seq.choose (fun (result, _, _) -> result)
This can be adopted to OP's requirements by providing also a result projection function.
let chunkBy2 (f : 'T-> 'Key) (g : 'T->'Result) =
chunkBy f >> Seq.map (fun (k, gs) -> k, List.map g gs)
// val chunkBy2 :
// f:('T -> 'Key) -> g:('T -> 'Result) -> (seq<'T> -> seq<'Key * 'Result list>)
// when 'Key : equality
["a", 1; "a", 2; "a", 111; "b", 3; "bb", 1; "bb", -1]
|> chunkBy2 fst snd
// val it : seq<string * int list> =
// seq [("a", [1; 2; 111]); ("b", [3]); ("bb", [1; -1])]
Seq.initInfinite (fun x ->
if (x / 2) % 2 = 0 then "a", x else "b", x)
|> chunkBy2 fst snd
|> Seq.skip 50000
// val it : seq<string * int list> =
// seq
// [("a", [100000; 100001]); ("b", [100002; 100003]); ("a", [100004; 100005]);
// ("b", [100006; 100007]); ...]

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

Resources