user614287
user614287

Reputation: 271

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

Upvotes: 1

Views: 373

Answers (3)

gileCAD
gileCAD

Reputation: 2493

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

Upvotes: 1

user614287
user614287

Reputation: 271

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)

Upvotes: 1

gileCAD
gileCAD

Reputation: 2493

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

Upvotes: 1

Related Questions