Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern matching vs record syntax function for data type field extraction

Tags:

haskell

Given an example data type with record syntax:

data VmInfo = VmInfo {infoVid   :: String
                     ,infoIndex :: Int
                     ,infoPid   :: Int
                     ,infoExe   :: String
                     } deriving (Show)

and (vmInfo :: String -> VmInfo) function that generates and returns the above data structure given vm name as string.

I can see two methods to extract the individual parts of the VmInfo data type.

(VmInfo vid _ _ _) <- vmInfo vm

Which is just a pattern match. And ...

vid <- infoVid <$> vmInfo vm

using record syntax compiler generated functions.

The question is simple: which is a preferred method?

Amount-of-typing wise they are the same so I am looking for speed and correctness/best practice.

I assume the pattern matching would be faster but then what is the point of record syntax?

like image 249
r.sendecky Avatar asked Apr 24 '12 03:04

r.sendecky


People also ask

How does pattern matching work in OCaml?

Pattern matching comes up in several places in OCaml: as a powerful control structure combining a multi-armed conditional, unification, data destructuring and variable binding; as a shortcut way of defining functions by case analysis; and as a way of handling exceptions.

What is pattern matching in Haskell?

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.

What does H :: t mean in OCaml?

The pattern h :: t matches any non-empty list, calls the head of the list h (one element, the first one), and the tail of the list t (zero or more elements after the first one). The operator :: is the list constructor (often called "cons"), which is why these patterns match lists.


1 Answers

These aren't semantically equivalent.

Let's look at the first example:

(VmInfo vid _ _ _) <- vmInfo vm

This performs a pattern match in the binding operation. There are two results of this. The first is that the constructor of the result of the vmInfo vm action is evaluated. This means that if vmInfo ended with a line like return undefined, the exception thrown by evaluating undefined would happen at this pattern match, not a later use of vid. The second is that if the pattern match is refuted (the pattern match does not match the value), the monad's fail instance will be called with the pattern match error text. That's not possible in this case, but it is generally possible when pattern matching a constructor in a bind.

Now, on to the next example:

vid <- infoVid <$> vmInfo vm

By the definition of <$>, this will be entirely lazy in the value returned by the action (not the effects). If vmInfo ended with return undefined, you wouldn't get the exception from evaluating undefined until you did something that used the value of vid. Additionally, if infoVoid had the ability to throw any exceptions, they wouldn't end up happening until the use of vid, best case.

Interestingly enough, these differences are only present in the scope of a monadic bind. If vmInfo was pure and you were binding the name vid inside a let or where expression, they would generate identical code.

In that case, which one you would want to use is entirely up to you. Both are idiomatic Haskell. People generally pick whichever looks better in the context they're working in.

The main reasons people use accessor functions is brevity when the record has so many fields a pattern match is huge, and because they are actual functions - they can be passed to any higher-order function their type fits into. You can't pass around pattern matches as a distinct construct.

like image 146
Carl Avatar answered Nov 15 '22 08:11

Carl