1{-# LANGUAGE FlexibleContexts #-}
4import Control.Applicative ( Applicative, (<$>), (<*>), (<|>) )
5import Control.Monad.State
7import qualified Data.Map as Map
8import qualified Data.Traversable as Traversable
9import qualified Data.UnionFind.IO as UF
11import qualified Type.Hint as Hint
16-- Holds a bunch of variables
17-- The rank of each variable is less than or equal to the pool's "maxRank"
18-- The young pool exists to make it possible to identify these vars in constant time.
22 , inhabitants :: [Variable]
29 { maxRank = outermostRank
34type Env = Map.Map String Variable
37-- Keeps track of the environment, type variable pool, and a list of errors
43 , sHint :: [Hint.Hint]
47initialState :: SolverState
51 , sSavedEnv = Map.empty
53 , sMark = noMark + 1 -- The mark must never be equal to noMark!
58modifyEnv :: (MonadState SolverState m) => (Env -> Env) -> m ()
60 modify $ \state -> state { sEnv = f (sEnv state) }
63modifyPool :: (MonadState SolverState m) => (Pool -> Pool) -> m ()
65 modify $ \state -> state { sPool = f (sPool state) }
68addHint :: Hint.Hint -> StateT SolverState IO ()
70 modify $ \state -> state { sHint = hint : sHint state }
73switchToPool :: (MonadState SolverState m) => Pool -> m ()
75 modifyPool (\_ -> pool)
78getPool :: StateT SolverState IO Pool
83getEnv :: StateT SolverState IO Env
88saveLocalEnv :: StateT SolverState IO ()
90 do currentEnv <- getEnv
91 modify $ \state -> state { sSavedEnv = currentEnv }
94uniqueMark :: StateT SolverState IO Int
97 let mark = sMark state
98 put $ state { sMark = mark + 1 }
102nextRankPool :: StateT SolverState IO Pool
105 return $ Pool { maxRank = maxRank pool + 1, inhabitants = [] }
108register :: Variable -> StateT SolverState IO Variable
110 do modifyPool $ \pool -> pool { inhabitants = variable : inhabitants pool }
114introduce :: Variable -> StateT SolverState IO Variable
117 liftIO $ UF.modifyDescriptor variable (\desc -> desc { rank = maxRank pool })
121flatten :: Type -> StateT SolverState IO Variable
123 flattenHelp Map.empty term
126flattenHelp :: Map.Map String Variable -> Type -> StateT SolverState IO Variable
127flattenHelp aliasDict term =
130 return (aliasDict ! name)
133 do maybeAlias' <- Traversable.traverse flattenAlias maybeAlias
134 liftIO $ UF.modifyDescriptor v $ \desc ->
135 desc { alias = maybeAlias' <|> alias desc }
138 TermN maybeAlias subTerm ->
139 do maybeAlias' <- Traversable.traverse flattenAlias maybeAlias
140 let localDict = maybe aliasDict (Map.fromList . snd) maybeAlias'
141 flatStructure <- traverseTerm (flattenHelp localDict) subTerm
144 liftIO . UF.fresh $ Descriptor
145 { structure = Just flatStructure
146 , rank = maxRank pool
151 , alias = maybeAlias'
155 flattenAlias (name, args) =
156 let flattenPair (arg, subTerm) =
157 (,) arg <$> flattenHelp aliasDict subTerm
159 (,) name <$> mapM flattenPair args
164makeInstance :: Variable -> StateT SolverState IO Variable
166 do alreadyCopied <- uniqueMark
167 freshVar <- makeCopy alreadyCopied var
168 restore alreadyCopied var
172makeCopy :: Int -> Variable -> StateT SolverState IO Variable
173makeCopy alreadyCopied variable = do
174 desc <- liftIO $ UF.descriptor variable
176 () | mark desc == alreadyCopied ->
182 "Error copying type variable. This should be impossible." ++
183 " Please report an error to the github repo!"
185 | rank desc /= noRank || flex desc == Constant ->
191 liftIO $ UF.fresh $ Descriptor
192 { structure = Nothing
193 , rank = maxRank pool
208 -- Link the original variable to the new variable. This lets us
209 -- avoid making multiple copies of the variable we are instantiating.
211 -- Need to do this before recursively copying the structure of
212 -- the variable to avoid looping on cyclic terms.
213 liftIO $ UF.modifyDescriptor variable $ \desc ->
214 desc { mark = alreadyCopied, copy = Just newVar }
216 -- Now we recursively copy the structure of the variable.
217 -- We have already marked the variable as copied, so we
218 -- will not repeat this work or crawl this variable again.
219 case structure desc of
224 do newTerm <- traverseTerm (makeCopy alreadyCopied) term
225 liftIO $ UF.modifyDescriptor newVar $ \desc ->
226 desc { structure = Just newTerm }
230restore :: Int -> Variable -> StateT SolverState IO Variable
231restore alreadyCopied variable =
232 do desc <- liftIO $ UF.descriptor variable
233 case mark desc /= alreadyCopied of
234 True -> return variable
236 do restoredStructure <-
237 Traversable.traverse (traverseTerm (restore alreadyCopied)) (structure desc)
238 liftIO $ UF.modifyDescriptor variable $ \desc ->
239 desc { mark = noMark, rank = noRank, structure = restoredStructure }
243traverseTerm :: (Monad f, Applicative f) => (a -> f b) -> Term1 a -> f (Term1 b)
258 Record1 fields ext ->
260 <$> Traversable.traverse (mapM f) fields
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