Haskell的monad可以被认为是使用并返回隐藏的状态参数吗?

AJM*_*AJM 9 monads state haskell

我不了解Haskell的monad背后的确切代数和理论.但是,当我考虑函数式编程时,我会得到这样的印象:状态将通过获取初始状态并生成它的副本来表示下一个状态.这就像将一个列表附加到另一个列表时; 两个列表都没有被修改,但是创建并返回了第三个列表.

因此,将monadic操作视为隐式地将初始状态对象作为参数并隐式返回最终状态对象是否有效?这些状态对象将被隐藏,以便程序员不必担心它们并控制它们的访问方式.因此,程序员不会像十分钟前那样尝试复制代表IO流的对象.

换句话说,如果我们有这个代码:

main = do
    putStrLn "Enter your name:"
    name <- getLine
    putStrLn ( "Hello " ++ name )
Run Code Online (Sandbox Code Playgroud)

...可以将IO monad和"do"语法看作代表这种代码风格吗?

putStrLn :: IOState -> String -> IOState
getLine :: IOState -> (IOState, String)
main :: IOState -> IOState

-- main returns an IOState we can call "state3"
main state0 = putStrLn state2 ("Hello " ++ name)
    where (state2, name) = getLine state1
        state1 = putStrLn state0 "Enter your name:"
Run Code Online (Sandbox Code Playgroud)

C. *_*ann 18

不,这不是monads一般的做法.但是,您的比喻,其实是完全正确的与问候的数据类型State s a,这恰好是一个单子.State定义如下:

newtype State s a = State { runState :: s -> (a, s) }
Run Code Online (Sandbox Code Playgroud)

...其中类型变量s是状态值,并且a是您使用的"常规"值.因此,"状态monad"中的值只是从初始状态到返回值和最终状态的函数.应用于monadic样式State只是通过一系列函数自动对状态值进行线程化.

ST单子是表面上类似,但使用魔法,以允许与计算真实的副作用,而只使得副作用不能从外部特定用途进行观察ST.

IO单子本质上是一个ST单子设置为"多魔",以副作用触摸外面的世界,只在一个点IO计算的运行,即在整个程序的入口点.尽管如此,在某种概念层面上,您仍然可以将其视为通过常规方式的函数来处理"状态"值State.

但是,其他monad不一定与线程状态,排序函数或诸如此类的东西有任何关系.成为monad所需的操作是非常通用和抽象的.例如,使用MaybeEither作为monad可以使用可能返回错误的函数,当发生错误时,monadic样式处理会从计算中逃避,这与处理State状态值的方式相同.使用列表作为monad会给你不确定性,让你同时将函数应用于多个输入并查看所有可能的输出,monadic样式自动将函数应用于每个参数并收集所有输出.


Gre*_*con 8

因此,将monadic操作视为隐式地将初始状态对象作为参数并隐式返回最终状态对象是否有效?

这似乎是学习单子的一个常见问题,试图弄清楚单个神奇的monad原始汤如何同时用于表示有状态计算,可能失败的计算,非确定性计算,异常,延续,排序副作用,以及等等.

通过一系列有状态计算的线程状态是满足monad定律的操作的一个单独示例.

你是正确的观察StateIOmonads是近亲,但如果你尝试插入列表monad,你的类比将会崩溃.