Guest User

Untitled

a guest
Feb 25th, 2018
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.48 KB | None | 0 0
  1. {-# LANGUAGE TupleSections #-}
  2.  
  3. import Control.Monad.State (State, evalState, get, gets, modify, put)
  4. import Data.Function (on)
  5. import Data.List (unionBy)
  6. import Data.Map (Map)
  7. import Data.Maybe (fromMaybe)
  8.  
  9. import qualified Data.Map as Map
  10.  
  11. type Name = String
  12.  
  13. data VLiteral
  14. = LInteger Integer
  15. | LBoolean Bool
  16. deriving (Show, Eq)
  17.  
  18. data Expr
  19. = ELam Name Expr
  20. | EApp Expr Expr
  21. | ELit VLiteral
  22. | EVar Name
  23. deriving (Show, Eq)
  24.  
  25. intLit = ELit . LInteger
  26.  
  27. data TLiteral
  28. = TInt
  29. | TBool
  30. deriving (Eq)
  31.  
  32. instance Show TLiteral where
  33. show TInt = "Int"
  34. show TBool = "Bool"
  35.  
  36. data Type
  37. = TLam Type Type
  38. | TVar Name
  39. | TLit TLiteral
  40. deriving (Eq)
  41.  
  42. instance Show Type where
  43. show (TLam a@TLam{} b) = "(" ++ show a ++ ")" ++ " -> " ++ show b
  44. show (TLam a b) = show a ++ " -> " ++ show b
  45. show (TLit lit) = show lit
  46. show (TVar name) = name
  47.  
  48. intTy = TLit TInt
  49. boolTy = TLit TBool
  50.  
  51. data Constraint
  52. = Constraint Type Type
  53.  
  54. cmap f (Constraint a b) = Constraint (f a) (f b)
  55.  
  56. instance Show Constraint where
  57. show (Constraint a b) = show a ++ " <=> " ++ show b
  58.  
  59. data ConState
  60. = ConState
  61. { conFreshId :: Int
  62. , conEnv :: Map Name Type
  63. } deriving (Show)
  64.  
  65. type Con a = State ConState a
  66.  
  67. freshTVar :: Con Type
  68. freshTVar = do
  69. i <- gets conFreshId
  70. modify (\s -> s { conFreshId = 1 + i })
  71. pure $ TVar ("a" ++ show i)
  72.  
  73. lookupType :: Name -> Con Type
  74. lookupType name = gets (fromMaybe notFound . Map.lookup name . conEnv)
  75. where
  76. notFound = error ("name not found: " ++ name)
  77.  
  78. insertType :: Name -> Type -> Con ()
  79. insertType name ty = do
  80. env <- gets conEnv
  81. modify (\s -> s { conEnv = Map.insert name ty env })
  82.  
  83. literalType :: VLiteral -> Type
  84. literalType (LInteger _) = intTy
  85. literalType (LBoolean _) = boolTy
  86.  
  87. scoped :: State s a -> State s a
  88. scoped action = do
  89. s <- get
  90. action <* put s
  91.  
  92. constrain :: Expr -> Con (Type, [Constraint])
  93. constrain (ELit lit) = pure (literalType lit, [])
  94. constrain (EVar name) = (, []) <$> lookupType name
  95. constrain (ELam var body) = do
  96. tvar <- freshTVar
  97. (tbody, ctrs) <- scoped (insertType var tvar *> constrain body)
  98. pure (TLam tvar tbody, ctrs)
  99. constrain (EApp left right) = do
  100. (lty, lctrs) <- constrain left
  101. (rty, rctrs) <- constrain right
  102. tvar <- freshTVar
  103. pure (tvar, lctrs ++ rctrs ++ [Constraint lty (TLam rty tvar)])
  104.  
  105. data Substitution
  106. = Substitution Name Type
  107.  
  108. subMap f (Substitution name ty) = Substitution name (f ty)
  109.  
  110. subName (Substitution name _) = name
  111.  
  112. instance Show Substitution where
  113. show (Substitution name ty) = name ++ " => " ++ show ty
  114.  
  115. applySub :: Substitution -> Type -> Type
  116. applySub (Substitution target ty) = go
  117. where
  118. go (TLam head body) = TLam (go head) (go body)
  119. go (TVar name) = if name == target then ty else TVar name
  120. go stuff = stuff
  121.  
  122. applySubs :: [Substitution] -> Type -> Type
  123. applySubs subs subject = foldr applySub subject subs
  124.  
  125. combine :: [Substitution] -> [Substitution] -> [Substitution]
  126. combine left right = right' `merge` left
  127. where
  128. right' = map (subMap (applySubs left)) right
  129. merge = unionBy ((==) `on` subName)
  130.  
  131. unify :: Type -> Type -> Either String [Substitution]
  132. unify tyA tyB
  133. | tyA == tyB = Right []
  134. | otherwise =
  135. case (tyA, tyB) of
  136. (TLam argA bodyA, TLam argB bodyB) -> do
  137. argSub <- unify argA argB
  138. bodySub <- unify (applySubs argSub bodyA)
  139. (applySubs argSub bodyB)
  140. Right $ combine bodySub argSub
  141. (TVar name, ty) -> Right $ [Substitution name ty]
  142. (ty, TVar name) -> Right $ [Substitution name ty]
  143. otherwise -> Left ("Cannot unify `" ++ show tyA ++ "` with `" ++ show tyB ++ "`")
  144.  
  145. solve :: [Constraint] -> Either String [Substitution]
  146. solve = go []
  147. where
  148. go final [] = Right final
  149. go final (Constraint a b:cs) = do
  150. sub <- unify a b
  151. go (combine sub final)
  152. (map (cmap $ applySubs sub) cs)
  153.  
  154. stdLib =
  155. Map.fromList
  156. [ ("add", TLam intTy (TLam intTy intTy))
  157. , ("gt", TLam intTy (TLam intTy boolTy))
  158. , ("if", TLam boolTy (TLam (TVar "a") (TLam (TVar "a") (TVar "a"))))
  159. , ("fix", TLam (TLam (TVar "b") (TVar "b")) (TVar "b"))
  160. ]
  161.  
  162. emptyConState = ConState 0 stdLib
  163.  
  164. infer :: Expr -> Either String Type
  165. infer expr =
  166. let (ty, ctrs) = evalState (constrain expr) emptyConState
  167. in (\cs -> applySubs cs ty) <$> solve ctrs
Add Comment
Please, Sign In to add comment