如何理解此状态中的 evalState Monad Haskell 代码片段?



我正在查看这个编译器代码片段,不明白evalState的作用,是 State Monad 的新手。

compileToAst :: FilePath -> String -> Either Errors (Contract (Check Type, Env, SourcePos))
compileToAst source code = case parse parser source code of
Right ast -> let ast'            = evalState ast [globals]
errors          = lefts $ map ann $ toList ast'
ann (a, _, pos) = a `extend` sourcePosPretty pos
in if null errors then Right ast' else Left errors
Left err  -> Left [(SyntaxError $ parseErrorTextPretty err, sourcePosPretty . NE.head $ errorPos err)]

假设有状态计算是s -> (a, s)的形式,ast是 monad,[globals]sevalState ast [globals]返回类型a。在哪里可以找到将s转换为新s并产生结果a的有状态计算定义?

函数evalState具有以下类型:

evalState :: State s a -> s -> a

第一个参数的类型,即State s a,实际上与函数类型s -> (a, s)同构。 这在形式上意味着存在两个在它们之间进行转换的函数:

runState :: State s a -> (s -> (a, s))
state :: (s -> (a, s)) -> State s a

如果你应用其中一个函数,然后应用另一个函数,你会得到你开始的东西(即,它们是逆函数,它们的组成是恒等函数)。

不太正式,这意味着无论您在哪里看到State s a,您都可以假装它是s -> (a, s)类型,反之亦然,因为您可以使用这些实用程序函数随意来回转换runStatestate.

因此,evalState所做的只是获取与有状态计算s -> (a, s)同构的第一个参数,并使用其第二个参数给出的初始状态运行它。 然后,它丢弃最终状态s并产生计算的最终结果。

由于它是第一个参数evalState这是有状态计算,因此实际上是parse parser source code成功时返回的ast,这就是您要查找的有状态转换s -> (a, s)

也就是说,ast具有的值类型:

ast :: State Env (Contract (Check Type, Env, SourcePos))

同构于:

ast :: Env -> (Contract (Check Type, Env, SourcePos), Env)

因此,它是一种有状态转换,它对由环境(符号表列表)组成的状态进行操作并生成合约。evalState所做的只是向这个有状态转换传递一个初始状态/环境,该状态/环境由表示全局符号表的单例组成,然后产生其最终合约结果(丢弃符号表的最终列表,因为一旦生成合约,它就不再重要了)。

因此,这个编译器的设计方式是,它将代码编译成一个"抽象语法树",它不是树状的数据结构,而实际上是一个函数,在产生契约的环境状态上给出有状态的转换;evalState只是"运行"转换以生成合约。

最新更新