3

I'm trying to learn some Template Haskell. As an exercise, I wrote a function that can generate things like isLeft and isRight (inspired by this question). Here's my humble attempt:

isA connam = do
    ConE nam <- connam
    nn <- newName "p"
    lamE [varP nn] $ caseE (varE nn) [
                       match (conP nam [wildP]) ( normalB [| True |] ) [],
                       match wildP ( normalB [| False |] ) [] 
                     ]

The problem is that it only works with one-argument constructors. The culprit is the conP nam [wildP] pattern. Ideally, it should look like conP nam (replicate (numArgs nam) wildP), where numArgs is a function returning the number of arguments of the constructor. But how do I write such a function? I imagine I need to access the relevant data declaration, but I have no idea how to.

There is another question about this very same function here.

Community
  • 1
  • 1
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243

1 Answers1

7

While you could use reify and examine the type to determine the arity of the data constructor, it's much easier to generate arity-independent code using a record pattern:

isFoo :: Bar -> Bool
isFoo p = case p of
    (Foo {}) -> True     -- Valid no matter what the arity of Foo is
    _        -> False

This can be done by replacing conP with recP in your code.

isA connam = do
    ConE nam <- connam
    nn <- newName "p"
    lamE [varP nn] $ caseE (varE nn) [
                       match (recP nam []) ( normalB [| True |] ) [],
                       match wildP ( normalB [| False |] ) [] 
                     ]
hammar
  • 138,522
  • 17
  • 304
  • 385