这样我们的类型检查函数的类型就是
Map Id Type -> Term -> Maybe Type. 如果可以赋型,
那么返回正确的类型, 如果类型错误返回 Nothing,
如果你想携带一些错误信息, 就可以把Maybe单子换成Either之类的东东,
这里我们就用最简单的Maybe即可.
这样我们可以把上面的规则转换成如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
typeTypingRule = MapIdType -> Term -> MaybeType
typingApp :: TypingRule typingApp ctx (App f x) = do-- Maybe 是个单子 fT <- typing ctx f case fT of (a :-> b) -> do xT <- typing ctx x if xT == a then return b else empty -- Maybe 是个 Alternative _ -> empty typingApp ctx _ = empty
如果要包含一些错误信息, 可以把类型改作:
MonadFail m => Map Id Type -> Term -> m Type, 并把
empty 换成 fail, 并填入错误信息.
如法炮制出其他的规则,
1 2 3 4 5 6 7 8 9 10 11 12 13
typingLam :: TypingRule typingLam ctx (Lam x t b) = do bT <- typing (insert x t ctx) b return (t :-> bT) typingLam ctx _ = empty
dataValue = VIntInt | VLamTy (forall m. (Monad m, Alternative m) => Value -> m Value) | NVarString
asTerm :: (Monad m, Alternative m) => Value -> m Term asTerm x = helper [] x where helper _ (NVar v) = pure $ Var v helper _ (VInt i) = pure $ IntLit i helper names (VLam t f) = let n = genName names "x"indo v' <- f (NVar n) v <- helper (n:names) v' pure $ Lam n t v
instanceShowValuewhere show x = maybe "Nothing" show (asTerm @Maybe x)
evalFunc :: Function evalFunc = Function { funcName = "eval" , aboveDefs = [ define [e| (c :* expr) ⊢ (x :* expr) ⇓ (t :* patt) |] `bindTo` [e| t .<- eval c x |] , define [e| (x :* expr) := (t :* patt) ∈ (c :*expr) |] `bindTo` [e| t .<- maybeAlt (M.lookup x c) |] ] , belowDefs = [ define [e| (c :* patt) ⊢ (x :* patt) ⇓ (t :* expr) |] `bindTo` [e| eval c x .:= t |] ] , bothDefs = [ define [e| λ (x :* expr) : (t :* expr) ↦ (b :* expr) |] `bindTo` [e| Lam x t b |] , define [e| (a :* expr) ⇒ (b :* expr) |] `bindTo` [e| Func a b |] , define [e| (c :* expr) <| (x :* expr) := (t :* expr) |] `bindTo` [e| insert x t c |] ] , rules = [ [e| x := v ∈ c |---------------| c ⊢ Var x ⇓ v |] , [e| True |-----------------------------------------------------------------| c ⊢ Lam x t v ⇓ VLam t (\xv -> maybeAlt $ eval (c <| x := xv) v) |] , [e| True |-------------------------| c ⊢ IntLit x ⇓ VInt x |] , [e| c ⊢ f ⇓ VLam _ fun /\ c ⊢ x ⇓ xv /\ ret .<- fun xv |-------------------------------------------------------| c ⊢ App f x ⇓ ret |] ] , argNames = ["c","x"] }
normalize :: Term -> Term normalize term = runIdentity (travTerm1 help (fromMaybe term (help1 term))) where help1 :: Term -> MaybeTerm -- If you defined more eliminator, add it here. help1 (App f arg) = case normalize f of Lam x t b -> pure $ normalize (subst (x, normalize arg) b) f' -> pure $ App f' (normalize arg) help1 _ = Nothing help x = case help1 x of Just x' -> pure x' _ -> pure $ normalize x
-- Alpha equivalent infix4 =*= (=*=) :: Term -> Term -> Bool (=*=) = alphaCtx M.empty where alphaCtx vars (Var a) (Var b) = caseM.lookup a vars of Just a' -> a' == b _ -> a == b alphaCtx vars (U l1) (U l2) = l1 == l2 alphaCtx vars (Pi n t b) (Pi n' t' b') = let vars' = insert n n' vars in alphaCtx vars t t' && alphaCtx vars' b b' alphaCtx vars (Lam n t b) (Lam n' t' b') = let vars' = insert n n' vars in alphaCtx vars t t' && alphaCtx vars' b b' alphaCtx vars (App f x) (App f' x') = alphaCtx vars f f' && alphaCtx vars x x' alphaCtx _ _ _ = False
-- Judgemental equality infix4 =~ (=~) :: Term -> Term -> Bool t =~ t' = normalize t =*= normalize t'