I am trying to create a typed expression parser in Haskell that works fine so far, but I'm currently trying to implement higher order functions. I swallowed the problem into a simple example:
{-# LANGUAGE TypeFamilies,GADTs,FlexibleContexts,RankNTypes #-} -- A function has an argument type and a result type class Fun f where type FunArg f type FunRes f -- Expressions are either constants of function applications data Expr a where Const :: a -> Expr a App :: Fun f => f -> FunArg f -> Expr (FunRes f) -- A very simple function data Plus = Plus -- Which takes two integer expressions and returns an integer expression instance Fun Plus where type FunArg Plus = (Expr Int,Expr Int) type FunRes Plus = Int -- A more complicated function which lifts a function to lists (like in haskell) data Map fr = Map f -- For this we need the concept of lifting function arguments: class Liftable a where type LiftRes a -- A singleton argument is lifted by changing the expression type from a to [a] instance Liftable (Expr a) where type LiftRes (Expr a) = Expr [a] -- Two function arguments are lifted by lifting each argument instance (Liftable a,Liftable b) => Liftable (a,b) where type LiftRes (a,b) = (LiftRes a,LiftRes b) -- Now we can declare a function instance for Map instance (Fun f,Liftable (FunArg f),r ~ LiftRes (FunArg f)) => Fun (Map fr) where type FunArg (Map fr) = r type FunRes (Map fr) = [FunRes f] -- Now a parser for functions: parseFun :: [String] -> (forall f. Fun f => f -> a) -> a -- The parser for the plus function is easy: parseFun ["plus"] f = f Plus -- But the parser for map is not possible: parseFun ("map":sym) f = parseFun sym (\fun -> f (Map fun))
It seems that the problem is that there is no way to convince the type controller that each LiftRes is itself Liftable, because declarations of recursive classes are forbidden.
My question is: how do I do this job? Are there other examples of typed expression parsers from which I could use hints?
EDIT: This discussion about family type restrictions seems very related. However, I cannot make my decision in my case, maybe someone can handle it?
henning
source share