如何理解 "m ()" 是一元计算
How to understand "m ()" is a monadic computation
来自document:
when :: (Monad m) => Bool -> m () -> m ()
when p s = if p then s else return ()
when
函数接受一个布尔参数和一个单元()
类型的单子计算,并且仅当布尔参数为True
时才执行计算。
===
作为一个 Haskell 新手,我的问题是对我来说 m ()
是一些 "void" 数据,但这里文档提到它是计算。是因为Haskell的懒惰吗?
懒惰与此无关。
m
/Monad 部分通常称为计算。
最好的例子可能是 m = IO
:
查看 putStrLn "Hello" :: IO ()
- 这是一个计算,当 运行 时,将在您的屏幕上打印 "Hello"
。
这个计算没有结果 - 所以 return 类型是 ()
现在写
hello :: Bool -> IO ()
hello sayIt =
when sayIt (putStrLn "Hello")
然后hello True
是一个计算,当运行时,将打印"Hello"
;而 hello False
是一种计算,当 运行 时什么都不做。
现在将其与 getLine :: IO String
进行比较 - 这是一种计算,当 运行 时,将提示您输入并将 return 输入作为 String
- 这就是为什么 return 类型是 String
.
这有帮助吗?
for me "m ()" is some "void" data
这有点道理,因为计算 是 一种特殊的数据。它与懒惰无关 - 它与上下文相关。
我们以State
为例。一个类型的函数,比如 s -> ()
in Haskell 只能产生一个值。但是,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)
Monads 非常抽象和数学化,因此关于它们的直观陈述通常是用相当模糊的语言进行的。因此,monadic 类型的值通常被非正式地标记为 "computations," "actions" 或(不太常见)"commands" 因为这是一个有时可以帮助我们推理它们的类比。但是,当您深入挖掘时,以这种方式使用会发现这些都是空话;最终他们的意思是 "some value of a type that provides the Monad
interface."
我更喜欢 "action" 这个词,所以让我继续吧。在 Haskell 中使用该词的直觉是:该语言区分 functions 和 actions:
- 函数不能有任何副作用,它们的类型类似于
a -> b
。
- 动作可能有副作用,它们的类型看起来像
IO a
。
- 这样做的结果:
IO ()
类型的操作会产生一个无趣的结果值,因此它要么是空操作(return ()
),要么是一个仅因为它而有趣的操作副作用。
Monad
然后是允许您将操作粘合在一起成为复杂操作的界面。
这一切都非常直观,但当您尝试将其应用于 IO
类型以外的许多 monad 时,这个类比就会变得相当牵强。例如,列表是一个单子:
instance Monad [] where
return a = [a]
as >>= f = concatMap f as
list monad 的 "actions" 或 "computations" 是……列表。列表如何成为 "action" 或 "computation"?在这种情况下类比很弱,不是吗?
所以我认为这是最好的建议:
- 明白"action"和"computation"是类比。没有严格的定义。
- 了解这些类比对于某些 monad 实例更强,而对于其他实例则较弱。
- 事物运作方式的最终晴雨表是
Monad
法则和与 Monad
一起使用的各种函数的定义。
来自document:
when :: (Monad m) => Bool -> m () -> m ()
when p s = if p then s else return ()
when
函数接受一个布尔参数和一个单元()
类型的单子计算,并且仅当布尔参数为True
时才执行计算。
===
作为一个 Haskell 新手,我的问题是对我来说 m ()
是一些 "void" 数据,但这里文档提到它是计算。是因为Haskell的懒惰吗?
懒惰与此无关。
m
/Monad 部分通常称为计算。
最好的例子可能是 m = IO
:
查看 putStrLn "Hello" :: IO ()
- 这是一个计算,当 运行 时,将在您的屏幕上打印 "Hello"
。
这个计算没有结果 - 所以 return 类型是 ()
现在写
hello :: Bool -> IO ()
hello sayIt =
when sayIt (putStrLn "Hello")
然后hello True
是一个计算,当运行时,将打印"Hello"
;而 hello False
是一种计算,当 运行 时什么都不做。
现在将其与 getLine :: IO String
进行比较 - 这是一种计算,当 运行 时,将提示您输入并将 return 输入作为 String
- 这就是为什么 return 类型是 String
.
这有帮助吗?
for me "m ()" is some "void" data
这有点道理,因为计算 是 一种特殊的数据。它与懒惰无关 - 它与上下文相关。
我们以State
为例。一个类型的函数,比如 s -> ()
in Haskell 只能产生一个值。但是,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)
Monads 非常抽象和数学化,因此关于它们的直观陈述通常是用相当模糊的语言进行的。因此,monadic 类型的值通常被非正式地标记为 "computations," "actions" 或(不太常见)"commands" 因为这是一个有时可以帮助我们推理它们的类比。但是,当您深入挖掘时,以这种方式使用会发现这些都是空话;最终他们的意思是 "some value of a type that provides the Monad
interface."
我更喜欢 "action" 这个词,所以让我继续吧。在 Haskell 中使用该词的直觉是:该语言区分 functions 和 actions:
- 函数不能有任何副作用,它们的类型类似于
a -> b
。 - 动作可能有副作用,它们的类型看起来像
IO a
。- 这样做的结果:
IO ()
类型的操作会产生一个无趣的结果值,因此它要么是空操作(return ()
),要么是一个仅因为它而有趣的操作副作用。
- 这样做的结果:
Monad
然后是允许您将操作粘合在一起成为复杂操作的界面。
这一切都非常直观,但当您尝试将其应用于 IO
类型以外的许多 monad 时,这个类比就会变得相当牵强。例如,列表是一个单子:
instance Monad [] where
return a = [a]
as >>= f = concatMap f as
list monad 的 "actions" 或 "computations" 是……列表。列表如何成为 "action" 或 "computation"?在这种情况下类比很弱,不是吗?
所以我认为这是最好的建议:
- 明白"action"和"computation"是类比。没有严格的定义。
- 了解这些类比对于某些 monad 实例更强,而对于其他实例则较弱。
- 事物运作方式的最终晴雨表是
Monad
法则和与Monad
一起使用的各种函数的定义。