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

问题描述 投票:-1回答:1

我正在看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是monad,[globals]s,而evalState ast [globals]返回类型a。我在哪里可以找到状态计算定义将s转换为新的s并产生结果a

haskell monads state-monad
1个回答
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)类型,反之亦然,因为你可以使用这些实用函数runStatestate来回转换。

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

因为它是evalState的第一个参数,即有状态计算,实际上astparse parser source code成功时返回,这是你正在寻找的状态转换s -> (a, s)

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

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

这是同构的:

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

所以它是一个有状态的转换,它在一个由一个环境(符号表列表)组成的状态上运行并产生一个契约。所有evalState都会通过这个有状态转换传递一个初始状态/环境,该状态/环境由表示全局符号表的单例组成,然后产生最终的合同结果(抛弃符号表的最终列表,因为一旦生成合同它就不再重要了) 。

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

© www.soinside.com 2019 - 2024. All rights reserved.