Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

constructor pattern matching haskell

Tags:

haskell

I have this data type

data Struct val =  Empty | Exec1 val
                         | Exec2 val 

And two dummy functions

apply :: Struct -> String
apply (Empty) = "matched Empty"  
apply (exec struct) = "matched Exec1 or Exec2"              

apply' :: Struct val -> String
apply' (Empty)   = "matched Empty"  
apply' (Exec1 _) = "matched Exec1"
apply' (Exec2 _) = "matched Exec2"

Second one is working fine, but the first one is causing error: "Parse error in pattern: exec". Can you plase explain why can't I match on constructor this way: apply (exec struct) = ... ?

It's causing a lot of boilerplate code when I have multiple constructors in my datatype and must pattern match them all separately.

like image 367
user1432699 Avatar asked Jun 05 '12 08:06

user1432699


3 Answers

Why? Because you can only match constructors, and exec is kind of a new variable. One reason for this is for example the following:

data Struct2 =  Empty | Exec1 String
                      | Exec2 Int

apply :: Struct2 -> String
apply Empty = "matched Empty"  
apply (exec struct) = ??

How should anyone know which of Exec1 and Exec2 you are matching? You couldn't apply functions here, since the actual type of struct couldn't be determined.

If you want to reduce the pattern matching, there are a number of ways, from using case, over different data implementation (like @Karolis suggested) and helper functions to higher level constructs with more complex types. But that's an endless topic.

like image 24
phipsgabler Avatar answered Oct 05 '22 23:10

phipsgabler


In general, if you have several constructors that share data, then it's usually better to refactor the data declaration to something like

data Struct val = Empty | NonEmpty StructType val
data StructType = Exec1 | Exec2

Now you can pattern match in apply like this

apply :: Struct -> String
apply (Empty) = "matched Empty"  
apply (NonEmpty exec struct) = "matched Exec1 or Exec2"

and you can still also pattern match to a specific Exec-type

apply' :: Struct val -> String
apply' (Empty)   = "matched Empty"  
apply' (NonEmpty Exec1 _) = "matched Exec1"
apply' (NonEmpty Exec2 _) = "matched Exec2"
like image 88
shang Avatar answered Oct 05 '22 23:10

shang


"exec" is not a type constructor and you can only use those in pattern matching.

What you can do is

data Struct val =  Empty | Exec Int val

apply :: Struct -> String
apply (Empty) = "matched Empty"  
apply (Exec _ _) = "matched Exec1 or Exec2"              

apply' :: Struct val -> String
apply' (Empty)   = "matched Empty"  
apply' (Exec 1 _) = "matched Exec1"
apply' (Exec 2 _) = "matched Exec2"
like image 39
Karolis Juodelė Avatar answered Oct 05 '22 23:10

Karolis Juodelė