简体   繁体   中英

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 ft" 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

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

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM