2

I need to count the number of Pat in a haskell Module. I know the simplest way is to pattern match on each level of the AST, which will result in a huge function that looks like the entire AST. I believe there's some way to take advantage of typeclasses like Functor or the State Monad to lean on some existing function that walks the tree (like prettyPrint) and trace a counter along, but I'm not sure how it works exactly.

ErikR
  • 51,541
  • 9
  • 73
  • 124
rem
  • 893
  • 4
  • 18
  • Suppose you get to a `PInfixApp pat1 qname pat2`... do you want to recurse into `pat1` and `pat2` or just stop? – ErikR Aug 02 '15 at 19:12
  • They have [`Data`](https://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Data.html#t:Data) instances, so you could use generics. – luqui Aug 02 '15 at 19:15
  • @user5402 I want to recurse – rem Aug 02 '15 at 19:16
  • @luqui can you elaborate? – rem Aug 02 '15 at 19:16
  • 3
    @rem, it will take a bit of learning. The [paper](http://research.microsoft.com/en-us/um/people/simonpj/papers/hmap/) (the 2003 one, at the bottom) is pretty good and easy to read. – luqui Aug 02 '15 at 19:20

1 Answers1

6

It's very easy using uniplate:

import Data.Data
import Data.Generics.Uniplate.Data
import Control.Monad
import Language.Haskell.Exts

findPats :: Data a => a -> [Pat]
findPats = universeBi

test = do
  content <- readFile "Simple.hs"
  case parseModule content of
    ParseFailed _ e -> error e
    ParseOk a       -> do
      forM_ (findPats a) $ \p -> do
        putStrLn $ "got a pat: " ++ show p

Essentially it's just the universeBi function.

ErikR
  • 51,541
  • 9
  • 73
  • 124