6import Control.Monad.Trans.Error
8import Data.List (foldl', foldl1')
9import qualified Data.Map as Map
10import System.IO.Unsafe
16typeCheck' s = str2expr s >>= typeCheck
19instance Monad (Either e) where
24typeCheck prog = unsafePerformIO $ do
25 tipe <- tc typeHints prog
27 Right t -> unify (ADT "Element") t
30guess = liftM GuessT (newIORef Nothing)
33 case Map.lookup x env of
34 Just t -> return $ Right t
35 Nothing -> liftM Right $ guess
36 -- return . Left $ "Variable '" ++ x ++ "' is not bound to a value!"
37 -- This is no good because some fundamental functions are only
38 -- defined in JS, but it is the right thing to do.
42tc :: Map.Map String Type -> Exp -> IO (Either String Type)
45 Number _ -> tipe NumberT
46 Var x -> varType env x
49 Boolean _ -> tipe BoolT
51 either_ts <- liftM sequence $ mapM (tc env) es
53 Right [] -> liftM (Right . ListT) guess
55 return . liftM ListT =<< foldl' func (return $ Right t) ts
58 case et of { Right t' -> unify t t'
60 Left err -> return $ Left err
61 Range start end -> return . liftM ListT =<< unifyWith env start end unify
62 Tuple es -> return . liftM TupleT . sequence =<< mapM (tc env) es
65 rList <- mapM (\(x,v) -> tc env v >>= tipe . (,) x) $
67 tipe . RecordT $ Map.fromList rList
70 let err = error $ "Field '" ++ x ++
71 "' does not exist in record '" ++ show t ++ "'."
73 RecordT tRec -> tipe $ Map.findWithDefault err x tRec
75 _ -> error $ "Expecting a record, but saw '" ++
76 show t ++ "' instead."
78 Binop op e1 e2 -> unifyWith env e1 e2 (checkBinop op)
79 Lambda x e -> do g <- guess
80 return . liftM (LambdaT g) =<< tc (Map.insert x g env) e
85 either_lam <- unify ta (LambdaT tb g)
86 case either_lam of { Right t -> return $ Right g
87 ; Left _ -> return either_lam }
88 Let x e1 e2 -> tc env (App (Lambda x e2) e1)
90 either_tb <- unifyWith env eb (Boolean True) unify
92 Right _ -> unifyWith env et ef unify
93 Left _ -> return either_tb
94 _ -> return . Right =<< guess
95 -- return . Left $ "Failure during type-checking: not implemented yet"
97unifyWith env e1 e2 f = do
100 case (t1, t2) of { (Right ta, Right tb) -> f ta tb
101 ; (Left _, _) -> return t1
102 ; (_, Left _) -> return t2 }
105check es = return . foldl1' f =<< sequence es
106 where f b e = case b of { Right _ -> e; Left _ -> b }
108checkBinop Cons t1 t2 = unify (ListT t1) t2
109checkBinop Append t1 t2 = check [guess >>= unify t1 . ListT, unify t1 t2]
110checkBinop Compose t1 t2 = do
111 ga <- guess; gb <- guess; gc <- guess
112 check [ unify t2 (LambdaT ga gb)
113 , unify t1 (LambdaT gb gc)
114 , tipe (LambdaT ga gc) ]
115checkBinop Apply t1 t2 = do { g <- guess
116 ; check [unify t1 (LambdaT t2 g), tipe g] }
118 | elem op [And, Or] = check [unify BoolT t1, unify BoolT t2]
119 | elem op [Equ, Neq] = check [guess >>= unify t1, unify t1 t2, tipe BoolT]
120 | elem op [Lt, Lte, Gt, Gte] =
121 check [unify NumberT t1, unify NumberT t2, tipe BoolT]
122 | elem op [Add, Sub, Mul, Div] = check [unify NumberT t1, unify NumberT t2]
128 (StringT, _) -> unify (ListT CharT) t2
129 (_, StringT) -> unify t1 (ListT CharT)
130 (ListT t1', ListT t2') -> return . fmap ListT =<< unify t1' t2'
131 (TupleT ts1, TupleT ts2) ->
132 return . fmap TupleT . sequence =<< zipWithM unify ts1 ts2
134 (RecordT tMap1, RecordT tMap2) ->
135 tipe . RecordT =<< unifyTmap tMap1 tMap2
138 if t2 `contains` ref then
139 return . Left $ "Cannot construct infinite type: " ++
140 show t1 ++ " = " ++ show t2
144 Just t1' -> unify t1' t2
145 Nothing -> writeIORef ref (Just t2) >> tipe t1
146 (_, GuessT ref) -> -- unify t2 t1
147 if t1 `contains` ref then
148 return . Left $ "Cannot construct infinite type: " ++
149 show t1 ++ " = " ++ show t2
153 Just t2' -> unify t1 t2'
154 Nothing -> writeIORef ref (Just t1) >> tipe t2
155 (LambdaT t1a t1b, LambdaT t2a t2b) -> do
158 return $ liftM2 LambdaT ta tb
159 (_, _) -> return . Left $
160 "Type Error: saw type '" ++ show t2 ++
161 "' but expecting type '" ++ show t1 ++ "'"
164 | Map.keysSet tMap1 /= Map.keysSet tMap2 =
165 error "record unification failed"
166 | otherwise = Map.intersectionWith unify tMap1 tMap2
170 ListT t' -> t' `contains` ref
171 TupleT ts -> any (`contains` ref) ts
172 LambdaT t1 t2 -> t1 `contains` ref || t2 `contains` ref
173 {- RecordT (Map.Map String Type)-}
174 GuessT ref' -> ref == ref'
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list