I'm trying to have some fun with dependently typed programming in Haskell, more specifically with type safe lookup operation. Previously, I've asked about how to implement a lookup operation for the following data type:
data Attr (xs :: [(Symbol,*)]) where
Nil :: Attr '[]
(:*) :: (Sing s, t) -> Attr xs -> Attr ('(s , t) ': xs)
And I've got the answer:
lookupAttr :: (Lookup s env ~ 'Just t) => Sing s -> Attr env -> t
lookupAttr s ((s', t) :* env') = case s %:== s' of
STrue -> t
SFalse -> lookupAttr s env'
That works fine. Now, I want to define a heterogeneous list of values of typed syntax, represented by type Exp
:
{-# LANGUAGE GADTs, TypeFamilies, DataKinds, TypeOperators, PolyKinds #-}
import Data.Singletons.Prelude.List
import Data.Singletons.Prelude.Bool
import Data.Singletons.Prelude.Eq
data Exp (env :: [(Symbol,*)]) :: * -> * where
Value :: String -> Exp env String
Var :: (Lookup s env ~ 'Just t) => Sing s -> Exp env t
Op :: Exp env t -> Exp env t -> Exp env t
The heterogeneous list type is defined by Env
data type:
data Env (env :: [(Symbol,*)]) where
Nil :: Env '[]
Cons :: (Lookup s' env ~ 'Nothing) =>
(Sing s' ,
Exp ('(s', a) ': env) a) ->
Env env ->
Env ('( s',a) ': env)
Using these data types, I define a lookup function using some sort of existential quantification (type Ex2
):
data Ex2 (p :: k -> k' -> *) where
Ex2 :: p e i -> Ex2 p
lookupEnv :: Lookup s env ~ 'Just t => Sing s -> Env env -> Ex2 Exp
lookupEnv s (Cons (s',e) env)
= case s %:== s' of
STrue -> Ex2 e
SFalse -> lookupEnv s env
So far, so good. Now, I arrive at some interesting problems:
1) Is there a way to define lookupEnv
without use this kind of existential quantification provided by type Ex2
?
2) Suppose that I want to define a operation for modifying a giving entry in a value of type Env
. The obvious attempt to define this function is
modifyEnv :: Lookup s env ~ 'Just t => Sing s -> Exp env t -> Env env -> Env env
modifyEnv s e (Cons (s',e') env')
= case s %:== s' of
STrue -> Cons (s', Op e e') env'
SFalse -> Cons (s',e') (modifyEnv s e env')
Function modifyEnv
compose some expression with another in the environment.
This function isn't accepted by GHC which returns a cryptic error message. How could I define such modification function?