如何理解这个 State Monad Haskell 代码片段中的 evalState?
How to understand evalState in this State Monad Haskell code snippet?
我正在查看 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]
returns 类型 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)
,反之亦然,因为您可以使用这些实用函数随意来回转换 runState
和 state
.
因此, evalState
所做的就是采用与有状态计算同构的第一个参数 s -> (a, s)
并使用其给出的初始状态运行它第二个参数。然后它丢弃最终状态 s
并产生计算的最终结果。
因为 evalState
的 first 参数是有状态的计算,所以实际上 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)
所以这是一个有状态的转换,它在一个由环境(符号列表 tables)组成的状态上运行并产生一个合约。 evalState
所做的就是将这个有状态转换传递给一个初始 state/environment ,该初始 state/environment 由表示全局符号 table 的单例组成,然后产生其最终合约结果(丢弃符号的最终列表 tables,因为一旦生成合同就不再重要了)。
因此,按照这个编译器的设计方式,它将代码编译成一个 "abstract syntax tree" ,而不是一个树状数据结构,实际上是一个函数,对产生的环境状态进行有状态转换合同; evalState
只是 "runs" 生成合同的转换。
我正在查看 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]
returns 类型 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)
,反之亦然,因为您可以使用这些实用函数随意来回转换 runState
和 state
.
因此, evalState
所做的就是采用与有状态计算同构的第一个参数 s -> (a, s)
并使用其给出的初始状态运行它第二个参数。然后它丢弃最终状态 s
并产生计算的最终结果。
因为 evalState
的 first 参数是有状态的计算,所以实际上 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)
所以这是一个有状态的转换,它在一个由环境(符号列表 tables)组成的状态上运行并产生一个合约。 evalState
所做的就是将这个有状态转换传递给一个初始 state/environment ,该初始 state/environment 由表示全局符号 table 的单例组成,然后产生其最终合约结果(丢弃符号的最终列表 tables,因为一旦生成合同就不再重要了)。
因此,按照这个编译器的设计方式,它将代码编译成一个 "abstract syntax tree" ,而不是一个树状数据结构,实际上是一个函数,对产生的环境状态进行有状态转换合同; evalState
只是 "runs" 生成合同的转换。