[Template-haskell] Polymorphism + Quasiquoting + Untyped AST = problems

Alfonso Acosta alfonso.acosta at gmail.com
Wed Feb 20 02:22:18 EST 2008


Hi,

Let me show you why I reached that conclusion through a simple example.

Imagine that, for some reason, we need to implement a DSL which is
required to use vectors. Furthermore, we would like to make
transformations/sanity checks at compile time.

To keep things simple, the vector is internally represented as a list:

newtype Vec a = MkVec [a] -- Note that MkVec would be hidden to the end user.

Using Template Haskell, we can easily create a constructor function
which fulfils all the requirements.

vector :: Lift a => [a] -> QExp
vector xs = do sanityCheck xs
                        [| MkVec xs |]
 where sanityCheck = undefined -- not specified


Using "vector" is simple:

$(vector [1,2,3,4,5])

OK, fair enough. However, pattern matching is lost and it would be
nicer to be able to to build vector literals using a syntax different
to lists. For example, using less-than and more-than symbols to
enclose the vector elements:

<1,2,3,4,5>

We would also like to do some pattern matching:

<>          -- empty vector
x <xs>   -- head and tail of the vector

Using a quasiquoter all the above is is possible. In the case of Int
vectors, supposing name our quasiquoter v we could do things like.

[$v|<1,2,3,4,5,6>|]

head  :: Vector Int -> Int
f v = case v of
          [$v|<>|] -> error "empty"
          [$v|x<xs>|] -> x

Looks nice, but we lose polymorphism! It is imposible  to make v work
with any instance of Read! Here is a possible implementation:

-- parse a list enclosed with lower-than and greater-than characters
parseLTGT :: Read a => String -> [a]
parseLTGT = undefined -- code ommited

v =  QuasiQuoter vExp vPat

-- In the case of Ints it is simple
vExp :: String -> Q Exp
vExp str = do let xs = (readLTGT str) :: [Int]
                      sanityCheck xs
                      [| MkVec xs |]

Unfortunately, we cannot implement vExpr in the general case. Removing
the explicit signature of readLTGT would lead to
ambiguous-type-variable errors.

Maybe things would be different if TH's AST wasn't untyped (i.e. vExpr
:: String -> Q (Exp a)) I'm not sure if it is feasible, though.

I would love to be proven wrong and read about a workaround/solution.
Any suggestions?

Cheers,

Fons


More information about the template-haskell mailing list