Wednesday, July 10, 2013

Exploring the compiler forest in Haskell

The combinators from the Compiler Forest paper can be implemented in Haskell as follows.  (Note: This requires recent GHC with options -XKindSignatures -XGADTs -XTypeFamilies.)
First, we define a type for partial compilers:

data PC :: * -> * -> * where
  PC :: (s -> (s', t' -> t)) -> PC (s,t) (s', t')


In Haskell terms, this is a "generalized algebraic data type", but this is solely so that we can think of PC as a two-argument type constructor instead of four.

We can introduce type families for extracting the source and target types from a pair:

type family Src a
type instance Src (s,t) = s

type family Tgt a
type instance Tgt (s,t) = t

applyPC :: PC p q -> 

          (Src p -> (Src q, Tgt q -> Tgt p))
applyPC (PC f) = f


The identity on partial compilers is:

idPC :: PC (s, t) (s, t)
idPC = PC (\s -> (s, id))


and composition of partial compilers is as follows:

compPC :: PC q r -> PC p q -> PC p  r
compPC (PC g) (PC f) =
  PC (\s -> let (s',f') =  f s in
            let (s'', g') =  g s' in
            (s'', f' . g'))



Likewise, tensor product of partial compilers can be defined.  First, we introduce a type family for tensors:

type family Tensor a b
type instance Tensor (s1,t1) (s2,t2) = 

                     ((s1,s2), (t1,t2))

tensorPC :: PC p1 p2 -> PC p1' p2' -> 

            PC (Tensor p1 p1') (Tensor p2 p2')
tensorPC (PC f) (PC g) =
  PC (\(x1,x2) -> 

        let (y1,f') = f x1 in
        let (y2,g') = g x2 in
        ((y1,y2),\(z1,z2) -> (f' z1, g' z2)))


The conditional combinator is:

condPC :: (Src p -> Bool) -> 
          PC p q -> PC p q -> PC p q
condPC p (PC f) (PC g) =
  PC (\s -> if p s then f s else g s)


and the (very similar) case combinator is:

casesPC :: (s -> Either s1 s2) -> 
           PC (s1,t) q -> 
           PC (s2,t) q -> PC (s,t) q
casesPC w (PC f) (PC g) =
  PC (\s -> case w s  
              of Left(s1) -> f s1 ;
                 Right(s2) -> g s2)


The "functor" operation that constructs a pair of functions $f:(s \to s')$ and $g:(t'\to t)$ to a partial compiler is:

functorPC :: (s -> s') -> (t' -> t) -> 
             PC(s,t) (s',t')
functorPC f g = PC (\s -> (f s,g))


and finally the iterator combinator is:

iterPC :: Int -> PC p p -> PC p p
iterPC 0 pc = pc
iterPC n pc = compPC pc (iterPC (n-1) pc)


Exercise for the reader: Implement some of the atomic partial compilers in Haskell and use the above combinators to combine them...

Labels: ,

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home