如何理解" m()"是一个monadic计算

时间:2015-10-19 09:05:28

标签: haskell monads

来自document

when :: (Monad m) => Bool -> m () -> m ()
when p s = if p then s else return ()

when函数采用布尔参数和单位()类型的monadic计算,并仅在布尔参数为True时执行计算。

===

作为Haskell的新手,我的问题是对我来说m ()是一些" void"数据,但这里文件提到它是计算。是因为Haskell的懒惰吗?

3 个答案:

答案 0 :(得分:6)

懒惰没有参与其中。

m / Monad部分通常称为计算

最好的例子可能是m = IO

查看putStrLn "Hello" :: IO () - 这是一项计算,运行时会将"Hello"打印到您的屏幕上。

此计算没有结果 - 因此返回类型为()

现在写的时候

hello :: Bool -> IO ()
hello sayIt =
   when sayIt (putStrLn "Hello")

然后hello True是一个计算,运行时会打印"Hello";而hello False是一个计算,运行时根本不会做任何事情。

现在将它与getLine :: IO String进行比较 - 这是一个计算,在运行时会提示您输入并将输入作为String返回 - 这就是返回类型为{{1 }}

这有帮助吗?

答案 1 :(得分:2)

  

对我而言“m()”是一些“无效”数据

这有点意义,因为计算一种特殊的数据。它与懒惰无关 - 它与背景有关。

我们以State为例。类型的函数,比如Haskell中的s -> ()只能生成一个值。但是,类型s -> ((), s)的函数是在s上执行某些转换的常规函数​​。您遇到的问题是,您只查看()部分,而s -> s部分则隐藏。这是State的重点 - 隐藏状态的传递。

因此,State s ()可以简单地转换为s -> ((), s)并返回,它仍然是Monad(计算),它产生的值为...... ()

如果我们看看实际用途,现在:

(flip runState 10) $ do
    modify (+1)

此表达式生成((), Int)的元组;隐藏了Int部分

它将修改状态,为其添加1。但它产生的中间值()适合您的when

when (5 > 3) $ modify (+1)

答案 2 :(得分:2)

Monads显然是抽象的和数学的,所以关于它们的直观陈述通常是用相当模糊的语言制作的。因此,monadic类型的值通常被非正式标记为"计算," "动作"或(不常见)"命令"因为这是一个类比,有时可以帮助我们推理它们。但是当你深入挖掘时,使用这种方式时这些都是空话;最终他们的意思是"提供Monad界面的某种类型的价值。"

我喜欢"动作"更好的是,让我顺其自然。在Haskell中使用该单词的直觉是:语言区分函数 actions

  1. 功能无任何副作用,其类型如a -> b
  2. 操作可能有副作用,其类型看起来像IO a
    • 这样做的结果:IO ()类型的操作会产生无趣的结果值,因此它既可以是无操作(return ()),也可以是仅有趣的操作,因为它的副作用。
  3. Monad然后是允许您将动作粘合在一起形成复杂动作的界面。

    这一切都非常直观,但是当你尝试将它应用于IO类型以外的许多单子时,它会变得相当紧张。例如,列表是monad:

    instance Monad [] where
      return a = [a]
      as >>= f = concatMap f as
    

    "行动"或"计算" monad列表是......列表。如何列出一个"动作"或者"计算"?在这种情况下,类比相当弱,不是吗?

    所以我说这是最好的建议:

    1. 了解"行动"和"计算"是类比。没有严格的定义。
    2. 明白这些类比对于某些monad实例更强,对其他实例则更弱。
    3. 关于事情如何运作的最终晴雨表是Monad法律以及与Monad一起使用的各种功能的定义。