Search code examples
haskellpattern-matchingrecordalgebraic-data-types

Haskell record pattern matching


I'm looking for a way to simplify function patterns when the actual data is not required:

data X = A | B String | C Int Int String
myfn :: X -> Int
myfn A = 50
myfn (B _) = 200
myfn (C _ _ _) = 500

Is there a way to make a simpler pattern for matching C, just discarding the values?

hsdev adds a hint "Hint: use record patterns", but Google did not help me there.


Solution

  • You can use record patterns like this:

    data X = A | B {name :: String} | C {x::Int, y::Int, name::String}
    
    myfn :: X -> Int
    myfn A = 50
    myfn B{} = 200
    myfn C{} = 500
    

    Record patterns allow you to give names to the fields of the constructors. you can also do things like:

    myfn C{name=n} = length n
    

    so you can see that you can pattern match only on the specific field you need.

    Note: you can use the empty record pattern even with data types that do not use record syntax:

    data A = A Int | B Int Int
    
    myfn A{} = 1
    myfn B{} = 2
    

    This is fine. There a number of other extensions related to record patterns:

    • RecordWildCards allows you to write things like C{..} which is equivalent to the pattern: C{x=x, y=y, name=name}, i.e. it matches all fields and you now have in scope x with the value matched for the x field etc.

    • NamedFieldPuns allows you to write C{name} to be equivalent to C{name=name}, so that name is now in scope and contains the value matched for the name field.

    Keep in mind that using record patterns doesn't prevent you from using your constructors in a positional way, so you can still write:

    myfn (B _) = 200
    

    It only adds functionality.