F#与复杂类型匹配

时间:2017-07-25 20:12:29

标签: f# pattern-matching

我是F#的新手,我尝试与复杂类型进行简单的模式匹配,但我找不到这样做的方法。请参阅下面的伪代码来解释我想要做的模式匹配。

type Vector= {X:int; Y:int}

let calculateDirection vector = 
match vector with
| vector.X=0 && vector.Y>0 -> "N"    // pseudo code 
| vector.X>0 && vector.Y>0 -> "NE"   // pseudo code 
| vector.X>0 && vector.Y=0 -> "E"    // pseudo code 
| vector.X>0 && vector.Y<0 -> "SE"   // pseudo code 
| vector.X=0 && vector.Y<0 -> "S"    // pseudo code 
| vector.X<0 && vector.Y<0 -> "SW"   // pseudo code 
| vector.X<0 && vector.Y=0 -> "W"    // pseudo code 
| vector.X<0 && vector.Y>0 -> "NW"   // pseudo code 
| _ -> "Error"

我阅读了一些教程(https://fsharpforfunandprofit.com/posts/match-expression/),但它总是很简单,并没有多大帮助。或者我只是不清楚它们。

提前致谢。

2 个答案:

答案 0 :(得分:6)

使用活动模式,您可以获得非常易读的代码:

type Vector= {X:int; Y:int}

let (|West|_|) v = if v.X < 0 then Some () else None
let (|East|_|) v = if v.X > 0 then Some () else None
let (|North|_|) v = if v.Y > 0 then Some () else None
let (|South|_|) v = if v.Y < 0 then Some () else None

let calculateDirection = function
    | North & East -> Some "NE"
    | North & West -> Some "NW"
    | North -> Some "N"
    | South & East -> Some "SE"
    | South & West -> Some "SW"
    | South -> Some "S"
    | East -> Some "E"
    | West -> Some "W"
    | _ -> None

答案 1 :(得分:4)

要与记录匹配,您可以使用记录匹配语法,这就像记录构造语法:

match vector with
| { X = x; Y = y } -> sprintf "Vector (%d, %d)" x y

你也可以将它与警卫结合起来:

match vector with
| { X = 0; Y = y } when y > 0 -> "N"
| { X = x; Y = y } when x > 0 && y > 0 -> "NE"
| { X = x; Y = 0 } when x > 0 -> "E"
...

但这看起来有点难看。为了帮助处理丑陋,你还可以构建自己的匹配器(又名“活动模式”) - 它们就像常规函数一样,但可以用于匹配。他们有一种有趣的语法:

let (|Positive|_|) x = if x > 0 then Some() else None
let (|Negative|_|) x = if x < 0 then Some() else None

match vector with
| { X = 0; Y = Positive } -> "N"
| { X = Positive; Y = Positive } -> "NE"
| { X = Positive; Y = 0 } -> "E"
| { X = Positive; Y = Negative } -> "SE"
...