This is a reference guide for how Purescript pattern matching works. Almost all of it was distilled from PureScript by Example by Phil Freeman the original developer of the Purescript compiler. I highly recommend reading it for in depth stuff. This is just for reference.
There are many types of simple patterns.
variable patterns are ones that bind arguments to a name like so:
wild card patterns matches any argument like a variable pattern, but does not bind a name to it
literal patterns match to specific values for example here are some Int, String, and Boolean literals:
Purescript supports guards like Haskell. Here is an example for the Euclidean algorithm:
In Purescript, you can apply some of the same patterns you can do on a Haskell list. The purescript Array is based on the JS Array, except it only take entries of a single type. PS also has a linked list that can be found in Data.List, which is like the Haskell List. This one is much more efficient. Anyway I digress! Here is some ways you can pattern match on an Array:
Note: Purescript does not support pattern matching with
cons (:) operator on
Data.Array! This is due to poor performance. :( You can use
Cons for pattern matching on Data.List using
Record patterns are used to match records. Recall a record is a light weight data structure, like so:
We can use record patterns to match records, like so:
Note: If we don't want to explicitly create a 'Person' type, we can also define
showPerson as such
Row polymorphism is the idea that a function can take a record with a variable number of rows, as long as the explicitly defined rows are matched. To give row polymorphism in the example above:
Now you can do this:
But not this:
Nested Patterns are exactly what you think. Array and Record patterns use them, but you can make them deep, like so:
You can bring additional names into scope with nested patterns by naming the array itself:
Here we have named the Array itself as well as pieces of its content.
Algebraic Datatypes offers the ability to maintain modularity while extending the functionality of an abstraction. It's helpful to understand it's benefit by comparing it with OO. Imagine we are working with shapes and we wanted to represent some common functionality all shapes will have. In an OO language we might do this:
Now imagine we decided that shapes should support perimeter. If we add
Shape then we would be forced to modify all of the classes that implement
Shape. This in a way breaks modularity.
With algebraic data types, we:
capture the various types of shapes in the datatype definition (use the
datakeyword to define a datatype):
and then add functionality to each of the shapes using pattern matching:
Notice you have access to the data you used to construct the shape with pattern matching. Neat, huh? It makes you think about what a concrete representation of an abstract idea really is. Really, what makes concrete representations of a single type different is the data needed to make them and their name.