如何在此州Monad Haskell代码段中了解evalState?

时间:2019-04-11 07:00:37

标签: haskell monads state-monad

我正在查看this compiler code snippet,但不了解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是单子,[globals]s,并且evalState ast [globals]返回类型a。在哪里可以找到将s转换为新s并产生结果a的状态计算定义?

1 个答案:

答案 0 :(得分:1)

函数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),反之亦然,因为您可以使用这些实用程序功能runState来回转换和state

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

由于是evalState first 参数是有状态计算,实际上是ast成功执行时返回的parse parser source code是有状态转换{{1} }您正在寻找。

也就是说,值s -> (a, s)的类型为:

ast

同构为:

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

所以这是一个有状态的转换,它在由环境(符号表列表)组成的状态下运行并产生合同。 ast :: Env -> (Contract (Check Type, Env, SourcePos), Env) 所做的所有事情就是通过此有状态转换,将一个初始状态/环境(由一个代表全局符号表的单例组成)传递给它,然后产生其最终的合同结果(丢弃符号表的最终列表,因为一旦合同已生成)。

因此,此编译器的设计方式是将代码编译为“抽象语法树”,该语法树不是树状数据结构,实际上是对产生契约的环境状态进行有状态转换的函数; evalState只是“运行”转换以生成合同。