Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 462
theduke Avatar asked Jun 27 '16 11:06

theduke


People also ask

Does Haskell have pattern matching?

Overview. We use pattern matching in Haskell to simplify our codes by identifying specific types of expression. We can also use if-else as an alternative to pattern matching. Pattern matching can also be seen as a kind of dynamic polymorphism where, based on the parameter list, different methods can be executed.

How does pattern matching work in Haskell?

Pattern matching consists of specifying patterns to which some data should conform and then checking to see if it does and deconstructing the data according to those patterns. When defining functions, you can define separate function bodies for different patterns.

What is a record Haskell?

Record accessors are just Haskell functions which are automatically generated by the compiler. As such, they are used like ordinary Haskell functions. By naming fields, we can also use the field labels in a number of other contexts in order to make our code more readable.

What is a guard in Haskell?

Haskell guards are used to test the properties of an expression; it might look like an if-else statement from a beginner's view, but they function very differently. Haskell guards can be simpler and easier to read than pattern matching .


1 Answers

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.

like image 59
Bakuriu Avatar answered Sep 22 '22 18:09

Bakuriu