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.
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.
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"
"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"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With