王文良
王文良

Reputation: 25

Usage about Pattern matching

I thought these two function were the same, but it seems that I was wrong. I define two function f and g in this way:

let rec f n k =
   match k with
   |_ when (k < 0) || (k > n) -> 0
   |_ when k = n -> 100
   |_ -> (f n (k+1)) + 1

let rec g n k =
   match k with
   |_ when (k < 0) || (k > n) -> 0
   | n -> 100
   |_ -> (g n (k+1)) + 1

let x = f 10 5
let y = g 10 5

The results are:

val x : int = 105
val y : int = 100

Could anyone tell me what's the difference between these two functions?


EDIT

Why does it work here?

let f x =
   match x with
   | 1 -> 100
   | 2 -> 200
   |_ -> -1

List.map f [-1..3]

and we get

val f : x:int -> int
val it : int list = [-1; -1; 100; 200; -1]

Upvotes: 1

Views: 128

Answers (2)

Joshua Taylor
Joshua Taylor

Reputation: 85853

The difference is that

match k with 
... 
when k = n -> 100

is a case that matches when some particular condition is true (k = n). The n used in the condition refers to the n that is bound as the function parameter. On the other hand

match k with 
...
n -> 100

is a case that only needs to match k against a pattern variable n, which can always succeed. The n in the pattern isn't the same n as the n passed into the function.

For comparison, try the code

let rec g n k =
   match k with
   |_ when (k < 0) || (k > n) -> 0
   | n -> n
   |_ -> (g n (k+1)) + 1

and you should see that when you get to the second case, the value returned is the value of the pattern variable n, which has been bound to the value of k.

This behavior is described in the Variable Patterns section of the MSDN F# Language Reference, Pattern Matching:

Variable Patterns

The variable pattern assigns the value being matched to a variable name, which is then available for use in the execution expression to the right of the -> symbol. A variable pattern alone matches any input, but variable patterns often appear within other patterns, therefore enabling more complex structures such as tuples and arrays to be decomposed into variables. The following example demonstrates a variable pattern within a tuple pattern.

let function1 x =
    match x with
    | (var1, var2) when var1 > var2 -> printfn "%d is greater than %d" var1 var2 
    | (var1, var2) when var1 < var2 -> printfn "%d is less than %d" var1 var2
    | (var1, var2) -> printfn "%d equals %d" var1 var2

function1 (1,2)
function1 (2, 1)
function1 (0, 0)

The use of when is described in more depth in Match Expressions.

Upvotes: 3

Darwing
Darwing

Reputation: 823

The first function is ok, it calls recursively itself n-k times and returns 100 when matches with the conditional where k = n. So, it returns all the calls adding 1 n-k times. with your example, with n=10 and k=5 it is ok the result had been 105.

The problem is the second function. I tested here. See I changed the pattern n->100 to z->100 and it still matches there and never calls itself recursively. So, it always returns 100 if it does not fail in the first conditional. I think F# don't allow that kind of match so it is better to put a conditional to get what you want.

Upvotes: 0

Related Questions