I'm new to F# and I'm trying to do a simple pattern matching with a complex type but I cannot find the way of doing it. See the pseudo code below to explain the pattern matching that i want to do.
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"
I read a few tutorials (https://fsharpforfunandprofit.com/posts/match-expression/) but it's always simple scenarios and does not help me much. Or I just don't understand them clearly.
Thanks in advance.
Using active patterns you can get very readable code like this:
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
To match with records, you can use record match syntax, which is just like record construction syntax:
match vector with
| { X = x; Y = y } -> sprintf "Vector (%d, %d)" x y
You can combine that with guards, too:
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"
...
But that looks a bit ugly. To help with the ugliness, you could also construct your own matchers (aka "active patterns") - which are just like regular functions, but can be used for matching. They have kind of a funny syntax:
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"
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With