【问题标题】:Do monads not guarantee the applicability of layered/non-layered monadic values to non-layered/non-monadic functions, and is this a good/bad thing?单子不保证分层/非分层单子值对非分层/非单子函数的适用性,这是好事还是坏事?
【发布时间】:2016-01-08 06:45:12
【问题描述】:

我只是想获得单子,所以如果我问了一个不好的问题,请耐心等待,但是...

如果单子只需要:

  • (a -> M a),其中 M 是一元类型构造函数,并且
  • (M a -> (a -> M b) -> M b),这是绑定操作(我理解为将单子映射到非单子到单子值函数)

...这是否意味着:

  • (M a -> a)
  • (M (M a) -> M a) 不是隐式必需的吗?

这通常不会引起问题吗?

  • 假设我们有一组函数 S,它们的类型都是 (x -> y),其中 x 和 y 是任意类型。

  • 现在,假设我使用一组单子函数 M 进行编程,其中它们的类型是 x -> M y

这是否意味着一旦我将一个类型转换为M y,我就不能使用任何(x -> y) 函数? 或者,我可以假设我可以做到(M x -> (x -> y) -> (y -> M y) -> M y)吗?

另外,我们在编程的时候不是一般都想提取原始类型吗?在async a -> amaybe a -> a 之类的东西之间切换时……这不是常见的操作吗?我绝对可以看到有人想要优化一个 monad 的情况,如果他们认为它可以忽略不计(例如,一个 logging monad)。

此外,没有扁平化的分层 monad 怎么样?我知道列表可以被视为限制展平的单子,这是一个明确且合乎逻辑的选择,但是async (async a) 单子值的假设情况如何,async 没有展平功能? bind 是否只意味着一层“一元还原”,我们通常可以假设(M a -> (a -> M a) -> M a) 通常可以视为(M a -> (M a -> a) -> (a -> M a) -> M a),而(M M a -> (a -> M a) -> M a or M M a) 可能不起作用?扁平化和非扁平化单子之间有真正的区别吗?

【问题讨论】:

  • 这个问题最好发布在cstheory.stackexchange.com 而不是这里。 Stack Overflow 更多的是关于实际编程问题。
  • M a -> a 不是必需的。并不是所有的 monad 都需要支持它。 M (M a) -> M a 可以派生自 returnbind(即 M a -> (a -> M b) -> M b BTW)。
  • @n.m.所以这意味着我不能使用(a -> b) 类型的函数集S?如果我需要将我的整个函数集引入单子函数集,这是否意味着我必须通过在某处应用单子构造函数来手动转换每个 (a -> b) -> (a -> M b)
  • 如果你曾经写过一个做 IO 的 Haskell 程序,你就知道你不必手动将每个函数都转换成a->IO b,.
  • 您可以用bindflatten 定义任何monad。这两种方式是等价的。如果你有bind,你可以用bind来定义flatten,反之亦然。

标签: monads


【解决方案1】:

这通常不会引起问题吗?

您可能会说这是“设计使然”。一种可能的用途是IO;一旦你的值被IO 污染,你就必须“冒泡”;您无法隐藏函数在纯值下进行 IO 的事实。


这是否意味着我必须通过在某处应用一元构造函数来手动转换每个 (a -> b) -> (a -> M b)?

这比你想象的要容易,因为每个 Monad 也是 Functor 和 Applicative Functor:

randomDice :: IO Int
randomDice = randomRIO (1,6)

cheat :: Int -> Int
cheat = (+1)

main = do
    dice <- randomDice
    dice' <- cheat <$> randomDice

拥有所有 fmap&lt;$&gt;liftA/liftMpure/return 机制供我们使用,它使得在单子上下文中轻松使用纯函数变得非常简单。


(M (M a) -&gt; M a) 不是隐式必需的

那个是假的。你只需要 bind 来实现它。

join              :: (Monad m) => m (m a) -> m a
join x            =  x >>= id

【讨论】:

  • stackoverflow.com/questions/10342876/… --- join 似乎是必需的,但在这里,它声明它可以由两者构建。但是 !== 可以吗,那么 {bind, return} 与 {bind, return, join} 不一样吗?
  • @VermillionAzure 后者只是有冗余。
  • 我试图做出的区别是等效与子集的区别。整数 可以 是浮点数,但它本身不是。它可以用强制转换隐式构造。同样,{bind, return} 的类型类有一个子类 {bind, return, join} 和一个额外的实现,但两者在定义上并不相同。这就像说所有计算机逻辑都可以从 NAND 门构造,但一切都不是 NAND。这更有意义吗?
  • @VermillionAzure 不,没有子类。 bindreturnjoin 必须遵守单子定律,即方程 join x = x &gt;&gt;= id 成立。
猜你喜欢
  • 2011-09-17
  • 2011-11-30
  • 2012-09-09
  • 1970-01-01
  • 2011-01-15
  • 2012-07-28
  • 1970-01-01
  • 1970-01-01
  • 2016-11-27
相关资源
最近更新 更多