Mapping haskell constructor templates

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" 

The second one works fine, but the first causes an error: "Analysis error in the template: exec". Can you explain why I cannot map the constructor this way: apply (exec struct) = ...?

This causes a lot of template code when I have several constructors in my data type, and they must match them individually.

+7
source share
5 answers

Why? Because you can only answer constructors, and exec is 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 to find out which of Exec1 and Exec2 do you match? You cannot apply functions here, since the actual type of struct cannot be defined.

If you want to reduce the correspondence of templates, there are several ways: from using case , from another data implementation (for example, proposed by K. Karolis) and auxiliary functions to higher-level constructions with more complex types. But this is an endless topic.

+3
source

In general, if you have several constructors that exchange data, then it’s usually best to reorganize the data declaration into something like

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

Now you can map the image to apply as follows

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

and you can also map the template to a specific type of Exec

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

"exec" is not a type constructor, and you can only use ones that match the pattern.

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" 
+3
source

In your specific case, you can do the following:

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

It will not scale well for more complex results.

+1
source
 apply Empty = "matched empty" apply (Exec1 _) = notEmpty apply (Exec2 _) = notEmpty notEmpty = "matched Exec1 or Exec2" 
0
source

All Articles