Search code examples
f#discriminated-unionactive-pattern

Curried Arguments in Discriminated Unions


I have a discriminated union like this:

type A = |B | C of int*A

I have to pattern match like this (the parenthesis appear to be needed):

match x with
| B -> printfn "B"
| C (i,a) -> printfn "%A, %A" i a

Is there a way to instead match like this with something like an active pattern:

match x with
| B -> printfn "B"
| C i a -> printfn "%A, %A" i a

And if not how come F# is designed such that this matching with curried arguments doesn't work and it instead forces you to use a tuple?

Edit: This was inspired by the F# list in which you can use h::t without any tupling or anything like that. And the source code is like:

type List<'T> = 
   | ([])  :                  'T list
   | (::)  : Head: 'T * Tail: 'T list -> 'T list

Solution

  • You cannot have whitespace as delimiter between bound patterns, because neither union cases nor active patterns support this. Syntax as per the F# spec:

    6.9.8 Evaluating Union Case

    Case(e1,…,en)

    7.2.3 Active Patterns

    (|CaseName|) arg1 ... argn inp
    (|CaseName|_|) arg1 ... argn inp

    So it's necessarily one tupled argument for a union case; and n+1 arguments for the banana function, of which n arguments are parameters. Only the last argument binds to the pattern. Consider:

    type X = B | C
    let (|C|) a b = C (a, b)
    let i = 42
    
    match C with
    | B -> printfn "B"
    | C i a -> printfn "%A, %A" i a // prints 42, (42, C)