aymericfraise
aymericfraise

Reputation: 33

Match any constructor

Given this type:

type typeT =
  | A of int
  | B of int
  | C of int
  | D of int

I want to simplify the following match (returning a default value when matching D, and the identity otherwise):

let match_example_1 t =
  match t with
  | A x -> A x 
  | B x -> B x 
  | C x -> C x 
  | D x -> D 1 
  ;;

Into something along the lines of this:

let match_example_2 t = 
  match t with
  | D x -> D 1 
  | f x -> f x
  ;;

Or this:

let match_example_3 t = 
  match t with
  | f x when f == D -> f 1
  | f x -> f x
  ;;

But i get a syntax error when matching f x. I'm guessing there's something about what constructors actually are in ocaml and the way pattern matching is actually done that i don't understand. I haven't managed to find the reason though, hopefully someone here can help out.

Upvotes: 0

Views: 225

Answers (4)

Et7f3XIV
Et7f3XIV

Reputation: 629

@Théo winterhalter You can use the as construct

match t with
| D _ -> D 1
| (A _ | B _ | C _) as x -> x

I’m on phone so can test where should be the as (inside or outside the parens).

Upvotes: 2

Aldrik
Aldrik

Reputation: 136

You can use the _ shortcut but you will loose the benefit of exhaustivity checking feature

You can also use something like

    match t with
    A x | B x | C x -> f x
    D x -> t 

This way if in the future the shape of your datastructure change, the type checker will help you in the refactoring process thanks to exhaustivity checking.

Upvotes: 0

glennsl
glennsl

Reputation: 29116

You could also just return the original value if it doesn't match what you're after:

match t with
| D _ -> D 1
| _   -> t

What you propose would only be useful if you want to manipulate the contained value, e.g. f x -> f (x + 1), but the questions I asked in the comment above still apply. What if there's a constructor that doesn't follow the exact same shape? What would you expect to happen if you add an E of string, or an F of int * string to typeT?

Upvotes: 1

Théo Winterhalter
Théo Winterhalter

Reputation: 5108

You cannot do what you want directly. You can factorise a bit by matching several things together.

match t with
| A x
| B x
| C x -> x 
| D x -> 1 

This will however not allow you to get the A, B or C.

You can however do something closer if you were storing your data differently.

type kind = A | B | C | D

type t = kind * int

And then do

match t with
| (D, x) -> (D, 1)
| (f, x) -> (f, x)

Upvotes: 0

Related Questions