summaryrefslogtreecommitdiff
path: root/lambda-calcul/haskell/src/Minilang/Lambda/Unify.hs
diff options
context:
space:
mode:
authorArnaud Bailly <arnaud@pankzsoft.com>2025-10-13 09:27:07 +0200
committerArnaud Bailly <arnaud@pankzsoft.com>2025-10-13 09:27:07 +0200
commit3a67e69bfe9492d2a2fc5e4b07cc8c909a346064 (patch)
tree8b4b0281dffe166f5c8495b1a5b892c1f8285870 /lambda-calcul/haskell/src/Minilang/Lambda/Unify.hs
parent21befc8c8ab2e91632f5341b4fa9425cf3c815ff (diff)
downloadlambda-nantes-3a67e69bfe9492d2a2fc5e4b07cc8c909a346064.tar.gz
add minimal evaluator and type inference
Diffstat (limited to 'lambda-calcul/haskell/src/Minilang/Lambda/Unify.hs')
-rw-r--r--lambda-calcul/haskell/src/Minilang/Lambda/Unify.hs57
1 files changed, 57 insertions, 0 deletions
diff --git a/lambda-calcul/haskell/src/Minilang/Lambda/Unify.hs b/lambda-calcul/haskell/src/Minilang/Lambda/Unify.hs
new file mode 100644
index 0000000..ad06552
--- /dev/null
+++ b/lambda-calcul/haskell/src/Minilang/Lambda/Unify.hs
@@ -0,0 +1,57 @@
+-- ported from https://www.cs.cornell.edu/courses/cs3110/2011sp/Lectures/lec26-type-inference/type-inference.htm
+module Minilang.Lambda.Unify where
+
+import Data.Text (Text)
+
+type Identifier = Text
+
+data Type
+ = TyVar Text
+ | Type :-> Type
+ deriving (Show, Eq)
+
+infixr 5 :->
+
+-- invariant: no identifier on the left hand-side can appear in
+-- an earlier term in the list, ie. the list is in "dependency order"
+-- and forms a DAG.
+type Substitution = [(Identifier, Type)]
+
+occurs :: Identifier -> Type -> Bool
+occurs x (TyVar y) = x == y
+occurs x (f :-> g) = occurs x f || occurs x g
+
+subst :: Type -> Identifier -> Type -> Type
+subst s x t@(TyVar y)
+ | x == y = s
+ | otherwise = t
+subst s x (f :-> g) = subst s x f :-> subst s x g
+
+apply :: Substitution -> Type -> Type
+apply subs t =
+ foldr (\(x, s) -> subst s x) t subs
+
+data UnifyError
+ = MismatchHead Text Text [Type] [Type]
+ | Circularity Identifier Type
+ deriving (Show, Eq)
+
+unifyOne :: Type -> Type -> Either UnifyError Substitution
+unifyOne (TyVar x) (TyVar y) = if x == y then Right [] else Right [(x, TyVar y)]
+unifyOne (f :-> g) (f' :-> g') =
+ unify [(f, f'), (g, g')]
+unifyOne (TyVar x) t =
+ if occurs x t
+ then Left $ Circularity x t
+ else Right [(x, t)]
+unifyOne t (TyVar x) =
+ if occurs x t
+ then Left $ Circularity x t
+ else Right [(x, t)]
+
+unify :: [(Type, Type)] -> Either UnifyError Substitution
+unify [] = Right []
+unify ((s, t) : rest) = do
+ sub2 <- unify rest
+ sub1 <- unifyOne (apply sub2 s) (apply sub2 t)
+ return $ sub1 ++ sub2