I'm trying to use some Haskell extensions to implement a simple DSL. A feature that I'd like is to have a type level context for variables. I know that this kind of thing is common place in languages like Agda or Idris. But I'd like to know if is possible to achieve the same results in Haskell.
My idea to this is to use type level association lists. The code is as follows:
{-# LANGUAGE GADTs,
DataKinds,
PolyKinds,
TypeOperators,
TypeFamilies,
ScopedTypeVariables,
ConstraintKinds,
UndecidableInstances #-}
import Data.Proxy
import Data.Singletons.Prelude
import Data.Singletons.Prelude.List
import GHC.Exts
import GHC.TypeLits
type family In (s :: Symbol)(a :: *)(env :: [(Symbol, *)]) :: Constraint where
In x t '[] = ()
In x t ('(y,t) ': env) = (x ~ y , In x t env)
data Exp (env :: [(Symbol, *)]) (a :: *) where
Pure :: a -> Exp env a
Map :: (a -> b) -> Exp env a -> Exp env b
App :: Exp env (a -> b) -> Exp env a -> Exp env b
Set :: (KnownSymbol s, In s t env) => proxy s -> t -> Exp env ()
Get :: (KnownSymbol s, In s t env) => proxy s -> Exp env t
test :: Exp '[ '("a", Bool), '("b", Char) ] Char
test = Get (Proxy :: Proxy "b")
Type family In
models a type level list membership constraint that is used to ensure that a variable can only be used if it is on a given environment env
.
The problem is that GHC constraint solver isn't able to entail the constraint
In "b" Char [("a",Bool), ("b",Char)]
for test
function, giving the following error message:
Could not deduce (In "b" Char '['("a", Bool), '("b", Char)])
arising from a use of ‘Get’
In the expression: Get (Proxy :: Proxy "b")
In an equation for ‘test’: test = Get (Proxy :: Proxy "b")
Failed, modules loaded: Main.
I'm using GHC 7.10.3. Any tip on how can I solve this or an explanation of why this isn't possible is highly welcome.