OR pattern matching - f#

I'm trying to use an OR pattern, as described here:
let foo = function
| Some (0, x) when x > 0 | None -> "bar"
| _ -> "baz"
However, this gives a compiler error:
error FS0010: Unexpected symbol '|' in pattern matching. Expected '->'
or other token.
What am I doing wrong? Does it have to do with the when guard?

A when guard refers to a single case, regardless of how many patterns are combined. The cases need to be separated:
let foo = function
| Some (0, x) when x > 0 -> "bar"
| None -> "bar"
| _ -> "baz"
For that reason, it may be better to factor out the return value, so a possibly complex expression isn't repeated:
let foo value =
let ret = "bar"
match value with
| Some (0, x) when x > 0 -> ret
| None -> ret
| _ -> "baz"
Using an active pattern is another way to avoid such repetition:
let (|Bar|_|) = function
| Some(0, x) when x > 0 -> Some()
| None -> Some()
| _ -> None
let foo = function
| Bar -> "bar"
| _ -> "baz"

You'll need two separate match cases there because the two cases bind different sets of variables (x and nothing, respectively):
| Some(0, x) when x>0 -> "bar"
| None -> "bar"

A nice trick I sometime use when you want to guard only specific bindings of a label, in a very complex pattern, is to use my own active patterns and the & (and) pattern operator:
let (|GreaterThan|_|) lowerLimit n =
if n > lowerLimit then Some () else None
let (|LesserThan|_|) upperLimit n =
if n < upperLimit then Some () else None
let (|GreaterOETo|_|) lowerLimit n =
if n >= lowerLimit then Some () else None
let (|LesserOETo|_|) upperLimit n =
if n <= upperLimit then Some () else None
let (|InRange|_|) (lowerLimit, upperLimit) n =
if n >= lowerLimit && n <= upperLimit then Some () else None
let (|Even|Odd|) n =
if n % 2 = 0 then
Even (n / 2)
else
Odd (n / 2)
type Union =
| A of int
| B of int
| A' of int
let getSpecialCases = function
| A (Even (x & GreaterThan 4 & LesserOETo 16))
| A (Odd (x & GreaterThan 0))
| B (x & LesserOETo 0)
| A' (Even (x & InRange (5, 16)))
| A' (Odd (x & GreaterThan 0)) -> Some x
| _ -> None
And of course you can just make a function to active pattern wrapper:
let (|P|_|) pred x =
if pred x then Some () else None
let ``match`` = function
| Even (x & pred (fun x -> x >= 7 && x <= 54)) -> Some x
| _ -> None

Related

recursion with several functions F#

I need some help with my hometask: to express one function (sort) through others (smallest, delete, insert). If you know how, please, tell me, how I can do running my recursion cicle? it doing now only one step. maybe something like this: val4 -> head :: tail |> sort tail on line 25 (val4)?
let rec smallest = function
| x :: y :: tail when x <= y -> smallest (x :: tail)
| x :: y :: tail when x > y -> smallest (y :: tail)
| [x] -> Some x
| _ -> None
let rec delete (n, xs) =
match (n, xs) with
| (n, x :: xs) when n <> x -> x :: delete (n, xs)
| (n, x :: xs) when n = x -> xs
| (n, _) -> []
let rec insert (xs, n) =
match (xs, n) with
| ([x], n) when x < n -> [x]#[n]
| (x :: xs, n) when x < n -> x :: insert (xs, n)
| (x :: xs, n) when x >= n -> n :: x :: xs
| (_, _) -> []
let rec sort = function
| xs -> let val1 = smallest xs
let val2 = val1.[0]
let val3 = delete (val2, xs)
let val4 = insert (val3, val2)
val4
let res = sort [5; 4; 3; 2; 1; 1]
printfn "%A" res
This is sort of like insertion sort, but since you're always finding the smallest number in the whole list instead of the next highest number, it will recurse forever unless you skip whatever you've already found to be the smallest.
Furthermore, your insert and delete functions act not on the item index, but on equality to the value, so it won't be able to handle repeated numbers.
Keeping most of your original code the same, usually you have an inner recursive function to help you keep track of state. This is a common FP pattern.
let sort lst =
let size = lst |> List.length
let rec sort' xs = function
| index when index = size -> xs
| index ->
let val1 = smallest (xs |> List.skip index)
let val2 = val1.[0]
let val3 = delete (val2, xs)
let val4 = insert (val3, val2)
sort' val4 (index + 1)
sort' lst 0
let res = sort [5; 3; 2; 4; 1; ]
printfn "%A" res
Needless to say, this isn't correct or performant, and each iteration traverses the list multiple times. It probably runs in cubic time.
But keep learning!
I found it... I only had changed 4 & 5 lines above in the "smallest" on this: | [x] -> Some x
| _ -> None, when there was: | [x] -> [x]
| _ -> []
let rec sort = function
| xs -> match xs with
| head :: tail -> let val1 = smallest xs
match val1 with
| Some x -> let val2 = delete (x, xs)
let val3 = insert (val2, x)
let val4 = (fun list -> match list with head :: tail -> head :: sort tail | _ -> [])
val4 val3
| None -> []
| _ -> []
// let res = sort [5; 4; 3; 2; 1]
// printfn "%A" res

Removing nested matches in F#?

Suppose I have types like this:
type C =
| W of int
| Z of int
type B =
{
C : C
D : int
}
type A =
| X of int
| Y of B
And I would like to do something for the Z case only:
let a =
Y
{
C = Z 123
D = 456
}
match a with
| X _ -> ()
| Y b ->
match b.C with
| W _ -> ()
| Z z -> printfn "%i" z
Is there a way to achieve this in a single match?
Can this be made more concise?
Yes, there is indeed! Patterns can be nested, that's their primary point. You can match on Y, and inside that match on the fields of B, and inside that match on C.
Like this:
match a with
| X _ -> ()
| Y { C = Z z } -> printfn "%i" z
| Y { C = W _ } -> ()
And since you're returning unit in both non-Y.C.Z cases, you can combine them in a catch-all pattern:
match a with
| Y { C = Z z } -> printfn "%i" z
| _ -> ()

Do I have to use an explicit match statement to identify its wildcard value?

Do I have to use an explicit match statement to identify its wildcard value?
For example, take the following function:
let (|Positive|Neutral|Negative|) = function
| x when x > 0 -> Positive
| x when x = 0 -> Neutral
| x when x < 0 -> Negative
| _ -> failwith (sprintf "unknown: %d" _)
Error:
Unexpected symbol '_' in expression
I learned that I can do this without any errors:
let (|Positive|Neutral|Negative|) v =
match v with
| x when x > 0 -> Positive
| x when x = 0 -> Neutral
| x when x < 0 -> Negative
| _ -> failwith (sprintf "unknown: %d" v)
UPDATE
Here's the result from a posted answer:
let (|Positive|Neutral|Negative|) = function
| x when x > 0 -> Positive
| x when x = 0 -> Neutral
| x when x < 0 -> Negative
| x -> failwith (sprintf "unknown: %d" x)
You can change it to this and it will work:
let (|Positive|Neutral|Negative|) = function
| x when x > 0 -> Positive
| x when x = 0 -> Neutral
| x when x < 0 -> Negative
| f -> failwith (sprintf "unknown: %d" f)

Why isn't pattern matching on an assigned value recognized [duplicate]

This question already has answers here:
Why doesn't pattern matching on a property of a record compile?
(2 answers)
Closed 6 years ago.
Why isn't pattern matching on an assigned value recognized
I receive a warning when I attempt to pattern match on the value called target:
[<Test>]
let ``set center cell to alive``() =
// Setup
let target = (2,2)
let grid = createGrid 9 |> Map.map (fun k v ->
match k with
| target -> { v with Status=Alive }
| _ -> v)
// Test
let center = grid |> getStatus (2,2)
// Verify
center |> should equal Alive
The warning points to:
| target -> { v with Status=Alive }
| _ -> v)
Specifically on:
| _ -> v)
The warning is:
This rule will never be reached.
Which forces me to not use target and instead hard-code the value in order to resolve the warning:
[<Test>]
let ``set center cell to alive``() =
// Setup
let grid = createGrid 9 |> Map.map (fun k v ->
match k with
| (2,2) -> { v with Status=Alive }
| _ -> v)
// Test
let center = grid |> getStatus (2,2)
// Verify
center |> should equal Alive
Can someone explain why I can't do this?
Full code:
type Status = Alive | Dead
type Cell = { X:int; Y:int; Status:Status }
let isNeighbor cell1 cell2 =
let isAbsNeighbor v1 v2 =
match abs (v1 - v2) with
| 0 | 1 -> true
| _ -> false
let isValueNeighbor v1 v2 =
match v1 >= 0
&& v2 >= 0 with
| true -> isAbsNeighbor v1 v2
| _ -> isAbsNeighbor v2 v1
match cell1.X <> cell2.X
|| cell1.Y <> cell2.Y with
| true -> isValueNeighbor cell1.X cell2.X
&& isValueNeighbor cell1.Y cell2.Y
| _ -> false
let createGrid rowCount =
[for x in 1..rowCount do
for y in 1..rowCount do
yield { X=x; Y=y; Status=Dead } ]
|> List.map (fun c -> (c.X, c.Y), { X=c.X; Y=c.Y; Status=Dead })
|> Map.ofList
let getStatus coordinate (grid:Map<(int * int), Cell>) =
match grid.TryFind coordinate with
| Some cell -> cell.Status
| None -> Dead
In a match expression, the rule
match k with
| target -> { v with Status=Alive }
unconditionally matches and binds k to a name target which shadows the existing definition. This means the following clause will never be reached. You can use a conditional match:
match k with
| t when t = target -> { v with Status = Alive }
| _ -> v
According to Pattern Matching your target is a variable pattern, so it shadows the original target value.
Pattern matching is useful for destructuring the matched object, for a simple test plain if-else is preferrable (in my opinion).
A use-case for pattern matching would be if you want to test several cases. Instead of a when guard you could then also use active patterns:
let (|Eq|_|) expected actual =
if expected = actual then Some()
else None
let target = (2,2)
let attempt = (3,2)
match attempt with
| Eq target -> Some "Bulls eye"
| (2, _) -> Some "Almost"
| t when fst t > 20 -> Some "Quite the contrary"
| _ -> None

Further optimizing Number to Roman Numeral function in F#

I'm new to F# and I'm curious if this can still be optimized further. I am not particularly sure if I've done this correctly as well. I'm curious particularly on the last line as it looks really long and hideous.
I've searched over google, but only Roman Numeral to Number solutions only show up, so I'm having a hard time comparing.
type RomanDigit = I | IV | V | IX
let rec romanNumeral number =
let values = [ 9; 5; 4; 1 ]
let capture number values =
values
|> Seq.find ( fun x -> number >= x )
let toRomanDigit x =
match x with
| 9 -> IX
| 5 -> V
| 4 -> IV
| 1 -> I
match number with
| 0 -> []
| int -> Seq.toList ( Seq.concat [ [ toRomanDigit ( capture number values ) ]; romanNumeral ( number - ( capture number values ) ) ] )
Thanks for anyone who can help with this problem.
A slightly shorter way of recursively finding the largest digit representation that can be subtracted from the value (using List.find):
let units =
[1000, "M"
900, "CM"
500, "D"
400, "CD"
100, "C"
90, "XC"
50, "L"
40, "XL"
10, "X"
9, "IX"
5, "V"
4, "IV"
1, "I"]
let rec toRomanNumeral = function
| 0 -> ""
| n ->
let x, s = units |> List.find (fun (x,s) -> x <= n)
s + toRomanNumeral (n-x)
If I had to use a Discriminated Union to represent the roman letters I would not include IV and IX.
type RomanDigit = I|V|X
let numberToRoman n =
let (r, diff) =
if n > 8 then [X], n - 10
elif n > 3 then [V], n - 5
else [], n
if diff < 0 then I::r
else r # (List.replicate diff I)
Then, based in this solution you can go further and extend it to all numbers.
Here's my first attempt, using fold and partial application:
type RomanDigit = I|V|X|L|C|D|M
let numberToRoman n i v x =
let (r, diff) =
if n > 8 then [x], n - 10
elif n > 3 then [v], n - 5
else [], n
if diff < 0 then i::r
else r # (List.replicate diff i)
let allDigits (n:int) =
let (_, f) =
[(I,V); (X,L); (C,D)]
|> List.fold (fun (n, f) (i, v) ->
(n / 10, fun x -> (numberToRoman (n % 10) i v x) # f i)) (n, (fun _ -> []))
f M
Here's a tail-recursive version of #Philip Trelford's answer:
let toRomanNumeral n =
let rec iter acc n =
match n with
| 0 -> acc
| n ->
let x, s = units |> List.find (fun (x, _) -> x <= n)
iter (acc + s) (n-x)
iter "" n

Resources