linuxxx
linuxxx

Reputation: 37

pattern matching and nesting pattern matching in OCaml

I have this OCaml code:


type primary_color = Red | Green | Blue

let r = Red

type point = float * float

type shape = 
    | Circle of {center : point; radius : float}
    | Rectangle of {lower_left : point; upper_right : point}
    
let c1 = Circle {center = (0., 0.); radius = 1.}

let r1 = Rectangle {lower_left = (-1., -1.); upper_right = (1., 1.)}


let avg a b = 
    (a +. b) /. 2.

and the following center functions that calculate the center of the different shapes:

(* Function one using let (...) = ... *)

let center s = 
    match s with 
    | Circle {center; radius} -> center
    | Rectangle {lower_left; upper_right} -> 
        let (x_ll, y_ll) = lower_left in
        let (x_ur, y_ur) = upper_right in 
        (avg x_ll x_ur, avg y_ll y_ur)


(* Function two using nested pattern matching Rec{ a = ..., b = ...} *)

let center s = 
    match s with 
    | Circle {center; radius} -> center
    | Rectangle {lower_left = (x_l, y_l); upper_right = (x_r, y_r)} -> 
        (avg x_l x_r, avg y_l y_r)
    | Point p -> p


I don't fully understand the way the pattern syntax is working here. how are in the first and second functions for calculating the center the values x_ll and y_ll just handed over to the function avg? Because a) the pair (x_ll, y_ll) isn't assigned to a variable and b) the values from the Pairs are just handed over without using for example let x_ll (a, b) = a

Upvotes: 0

Views: 315

Answers (1)

Chris
Chris

Reputation: 36536

Both center functions are accomplishing the same thing. The first one is just being a bit more roundabout. Though the first one doesn't match against Point which your earlier code doesn't define.

If you still needed the names for the two tuples, you could use as.

let center s = 
    match s with 
    | Circle {center; radius} -> center
    | Rectangle {lower_left  = (x_l, y_l) as ll; 
                 upper_right = (x_r, y_r) as ur} -> 
        (avg x_l x_r, avg y_l y_r)

Structural pattern matching is very powerful, and it isn't limited to a certain number of levels. Consider a very simple example.

type a = {b: int}
type c = {d: a}
type e = {f: c}

let g = {f={d={b=42}}}

We can match directly to that int.

match g with
| {f={d={b=n}}} -> n

Or even leave out the =n.

match g with
| {f={d={b}}} -> b

We can also do this in a let binding.

let {f={d={b=n}}} = g in
n

Upvotes: 2

Related Questions