pmichaels
pmichaels

Reputation: 139

Converting Haskell to Template Haskell: couldn't match expected type ExpQ

I had the following Haskell code (just a fragment of all code, but works):

data ByteCode t where
    INT :: Int -> ByteCode Int
    BOOL:: Bool -> ByteCode Bool
    Add :: ByteCode Int -> ByteCode Int -> ByteCode Int
    Mul :: ByteCode Int -> ByteCode Int -> ByteCode Int


newtype C t = C (Int -> (ByteCode t, Int)) 
unC (C t) = t



instance Symantics C where
    int x  = C(\vc -> (INT x, vc))
    bool b = C(\vc -> (BOOL b, vc))

    add e1 e2 = C(\vc -> let (e1b,vc1) = unC e1 vc
                             (e2b,vc2) = unC e2 vc1
                         in (Add e1b e2b,vc2))

    mul e1 e2 = C(\vc -> let (e1b,vc1) = unC e1 vc
                             (e2b,vc2) = unC e2 vc1
                         in (Mul e1b e2b,vc2))

I am trying to convert it to Template Haskell. Specifically I wanted to get rid of the ByteCode and just use ExpQ (new to me) Template Haskell type. So now I have:

    newtype C a = C ExpQ
    
    unC (C x) = x

I'm trying to update the instance, so my new code is:

newtype C t = C ExpQ
unC (C t) = t



instance Symantics C where
    int x  = C(\vc -> (ExpQ x, vc))
    bool b = C(\vc -> (ExpQ b, vc))

    add e1 e2 = C(\vc -> let (e1b,vc1) = unC e1 vc
                             (e2b,vc2) = unC e2 vc1
                         in (Add e1b e2b,vc2))

But I am getting a lot of Couldn't match expected type ‘Q Exp’ with actual type ‘t1 -> (t0, t1)’ errors. How can I best write this new instance?

Upvotes: 1

Views: 156

Answers (1)

K. A. Buhr
K. A. Buhr

Reputation: 50819

In the original C type, there was an integer "state" threaded through the computation, meaning that the C newtype actually wrapped a function of type:

Int -> (ByteCode t, Int)

The expressions:

C (\vc -> ...)  -- C constructor takes a function

and

unC e1 vc   -- unC e1 gets the function, and it's applied to vc

in the original code reflected this.

In your new C type, you've removed the state, and the C newtype is just an ExpQ, but you haven't updated any of the code to reflect this change, so you are getting type mismatch errors between ExpQ (the type wrapped by your new C) and functions of the form Int -> (ByteCode t, Int) (the type wrapped by the old C).

You might get closer to your intended goal with something like:

instance Symantics C where
  int x  = C $ litE (IntegerL (fromIntegral x))
  bool False = C [|False|]
  bool True  = C [|True|]
  add e1 e2 = C [|$(unC e1) + $(unC e2)|]

Upvotes: 1

Related Questions