Created
December 14, 2022 16:21
-
-
Save chrisdone-artificial/b4f10e10e30d595d9cdf32cd51818738 to your computer and use it in GitHub Desktop.
attempts to add polytypes to lambda
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- original from <https://www.cs.ox.ac.uk/projects/gip/school/tc.hs> but URLs don't last long in academia | |
-- | |
{-# LANGUAGE ExistentialQuantification,GADTs,TypeOperators #-} | |
-- This typechecker, written by Stephanie Weirich at Dagstuhl (Sept 04) | |
-- demonstrates that it's possible to write functions of type | |
-- tc :: String -> Term a | |
-- where Term a is our strongly-typed GADT. | |
-- That is, generate a typed term from an untyped source; Lennart | |
-- Augustsson set this as a challenge. | |
-- | |
-- In fact the main function goes | |
-- tc :: UTerm -> exists ty. (Ty ty, Term ty) | |
-- so the type checker returns a pair of an expression and its type, | |
-- wrapped, of course, in an existential. | |
module Main where | |
import Data.Typeable | |
-- Untyped world -------------------------------------------- | |
data UTerm = UVar String | |
| ULam String UType UTerm | |
| UApp UTerm UTerm | |
| UConBool Bool | |
| UIf UTerm UTerm UTerm | |
| UTLam String UTerm | |
| UTApp UTerm UType | |
data UType = UBool | UArr UType UType | UVarTy String | |
-- Type to term functions | |
data t :-> a | |
data Type | |
-- Typed world ----------------------------------------------- | |
data Ty t where | |
Bool :: Ty Bool | |
Arr :: Ty a -> Ty b -> Ty (a -> b) | |
Type :: String -> Ty Type | |
TypeVar :: String -> Var g t -> Ty t | |
instance Show (Ty t) where show = showType | |
data Term g t where | |
Var :: Var g t -> Term g t | |
Lam :: Ty a -> Term (g,a) b -> Term g (a->b) | |
App :: Term g (s -> t) -> Term g s -> Term g t | |
ConBool :: Bool -> Term g Bool | |
If :: Term g Bool -> Term g a -> Term g a -> Term g a | |
TypeTerm :: Ty a -> Term g Type | |
data Var g t where | |
ZVar :: Var (h,t) t | |
SVar :: Var h t -> Var (h,s) t | |
deriving instance Eq (Var g t) | |
instance Show (Var g t) where | |
show v = "v" ++ show (go v) where | |
go :: forall g t. Var g t -> Int | |
go ZVar = 0 | |
go (SVar v) = 1 + go v | |
data Typed thing = forall ty. Typed (Ty ty) (thing ty) | |
-- Typechecking types | |
data ExType = forall t. ExType (Ty t) | |
tcType :: TyEnv g -> UType -> ExType | |
tcType e (UVarTy s) = case lookupVar s e of Typed t v -> ExType $ TypeVar s v | |
tcType _ UBool = ExType Bool | |
tcType e (UArr t1 t2) = case tcType e t1 of { ExType t1' -> | |
case tcType e t2 of { ExType t2' -> | |
ExType (Arr t1' t2') }} | |
-- The type environment and lookup | |
data TyEnv g where | |
Nil :: TyEnv g | |
Cons :: String -> Ty t -> TyEnv h -> TyEnv (h,t) | |
lookupVar :: String -> TyEnv g -> Typed (Var g) | |
lookupVar _ Nil = error "Variable not found" | |
lookupVar v (Cons s ty e) | |
| v==s = Typed ty ZVar | |
| otherwise = case lookupVar v e of | |
Typed ty v -> Typed ty (SVar v) | |
data Equal a b where | |
Equal :: Equal c c | |
cmpTy :: Ty a -> Ty b -> Maybe (Equal a b) | |
cmpTy Bool Bool = Just Equal | |
cmpTy (Type s) (Type t) | s == t = Just Equal | otherwise = Nothing | |
cmpTy (TypeVar s v) (TypeVar t v') = do | |
undefined | |
cmpTy (Arr a1 a2) (Arr b1 b2) | |
= do { Equal <- cmpTy a1 b1 | |
; Equal <- cmpTy a2 b2 | |
; return Equal } | |
cmpTy a b = error $ "cmpTy: " ++ show (a,b) | |
-- Typechecking terms | |
tc :: UTerm -> TyEnv g -> Typed (Term g) | |
tc (UVar v) env = case lookupVar v env of | |
Typed ty v -> Typed ty (Var v) | |
tc (UConBool b) env | |
= Typed Bool (ConBool b) | |
tc (ULam s ty body) env | |
= case tcType env ty of { ExType bndr_ty' -> | |
case tc body (Cons s bndr_ty' env) of { Typed body_ty' body' -> | |
Typed (Arr bndr_ty' body_ty') | |
(Lam bndr_ty' body') }} | |
tc (UApp e1 e2) env | |
= case tc e1 env of { Typed (Arr bndr_ty body_ty) e1' -> | |
case tc e2 env of { Typed arg_ty e2' -> | |
case cmpTy arg_ty bndr_ty of | |
Nothing -> error "Type error" | |
Just Equal -> Typed body_ty (App e1' e2') }} | |
tc (UIf e1 e2 e3) env | |
= case tc e1 env of { Typed Bool e1' -> | |
case tc e2 env of { Typed t2 e2' -> | |
case tc e3 env of { Typed t3 e3' -> | |
case cmpTy t2 t3 of | |
Nothing -> error "Type error" | |
Just Equal -> Typed t2 (If e1' e2' e3') }}} | |
tc (UTLam s body) env | |
= let bndr_ty' = Type s in | |
case tc body (Cons s bndr_ty' env) of { Typed body_ty' body' -> | |
Typed (Arr bndr_ty' body_ty') | |
(Lam bndr_ty' body') } | |
tc (UTApp e1 arg_ty) env | |
= case tcType env arg_ty of | |
ExType arg_ty' -> | |
case tc e1 env of { Typed t1'@(Arr (Type s) _) e1' -> | |
instantiate t1' e1' s arg_ty' | |
} | |
instantiate :: forall a b g. Ty (Type -> a) -> Term g (Type -> a) -> String -> Ty b -> Typed (Term g) | |
instantiate (Arr Type{} ty') e arg_name arg = go ty' (App e (TypeTerm arg)) where | |
go :: forall x. Ty x -> Term g x -> Typed (Term g) | |
go t (Lam ty e) = Typed (subst arg_name arg t) (Lam (subst arg_name arg ty) (substE arg_name arg ty e) | |
go t ex = Typed t ex | |
subst :: String -> Ty a -> Ty b -> ExType | |
subst = ... | |
showType :: Ty a -> String | |
showType (TypeVar s v) = s | |
showType Bool = "Bool" | |
showType (Type v) = "(" ++ show v ++ " :: Type)" | |
showType (Arr t1 t2) = "(" ++ showType t1 ++ ") -> (" ++ showType t2 ++ ")" | |
uNot = ULam "x" UBool (UIf (UVar "x") (UConBool False) (UConBool True)) | |
uId = UTLam "t" (ULam "x" (UVarTy "t") (UVar "x")) | |
testId = UApp (UTApp uId UBool) (UConBool True) | |
test :: UTerm | |
test = UApp uNot (UConBool True) | |
main = putStrLn (case tc testId Nil of | |
Typed ty _ -> showType ty | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment