haskell - 'Chaining operations' 是 Monad 类解决的 "only"吗?

标签 haskell functional-programming monads

为了澄清这个问题:它是关于 monad 类型类的优点(而不是没有统一类的实例)。

在阅读了许多引用资料后(见下文),
我得出的结论是,实际上,单子(monad)类 有没有解决的仅限 一,但大而关键 , 问题:具有上下文的类型上的函数“链接” .因此,著名的句子“单子(monad)是可编程的分号”。
事实上,一个monad可以看成an array of functions with helper operations .

我坚持单子(monad)之间的区别类(class) ,理解为其他类型的通用接口(interface);以及实例化类的这些其他类型(因此,“一元类型”)。

我知道 monad 类本身只能解决运算符的链接,因为主要是它只要求它的类型实例
拥有bind >>=return ,并告诉我们他们必须如何表现。作为奖励,编译器极大地帮助了编码提供 do monadic 类型的符号。

另一方面,
它是 每个 单个类型实例化 monad 类,解决 每个具体问题 , 但不仅仅是因为是 Monad 的一个实例.例如 Maybe解决“函数如何返回值或错误”,State解决了“如何使函数具有全局状态”,IO解决“如何与外界交互”等问题。所有这些类都在上下文中封装了一个值。

但迟早,我们将需要对此类上下文类型进行链接操作。即,我们需要按特定顺序组织对这些类型的函数的调用(有关此类问题的示例,请阅读 You could have invented monads 中有关多值函数的示例)。

如果你让每种类型都是 monad 类的实例,你就解决了链接问题。
要使链接正常工作,您需要 >>=只有它拥有的确切签名,没有其他。 (见 this question)。

因此,我猜下次您定义上下文数据类型 T 来解决问题时,如果您需要对函数的调用进行排序(在 T 的值上),请考虑将 T 设为 Monad 的实例。 (如果您需要“选择链接”并且可以从 do 符号中受益)。为了确保你做对了,检查 T 是否满足 monad laws

然后,我向 Haskell 专家提出两个问题:

  • 一个具体的问题:单子(monad)类是否有其他问题由 ifself 解决(除了单子(monad)类)?如果有的话,那么它与链接操作问题的相关性如何?
  • 一个可选的一般性问题:我的结论是否正确,我是否误解了什么?

  • 引用

    教程
  • Monads in pictures绝对值得;先读这个。
  • Fistful of monads
  • You could have invented monads
  • Monads are trees (pdf)

  • StackOverflow 问答
  • How to detect a monad
  • On the signature of >>= monad operator
  • 最佳答案

    你肯定是在用你所说的方式做一些事情——有很多事情Monad意味着你已经很好地将它们分开了。

    也就是说,我肯定会说链接操作不是 Monads 解决的主要问题。这可以使用普通的 Functor(有一些麻烦)或使用 Applicatives 轻松解决。 当“选择链接”时,您需要使用完整的 monad 规范。 尤其是Applicative 之间的紧张关系。和 Monad来自 Applicative需要静态了解副作用计算的整个结构。 Monad可以在运行时更改该结构,从而牺牲一些可分析性来换取权力。

    为了更清楚地说明这一点,您处理 Monad 但不是任何特定 monad 的唯一地方是,如果您定义的多态性限制为 Monad .这在 Control.Monad 中反复出现。模块,所以我们可以从那里检查一些例子。

    sequence     :: [m a] -> m [a]
    forever      :: m a   -> m b
    foldM        :: (a -> b -> m a) -> a -> [b] -> m a
    

    马上,我们可以扔掉sequence尤其是 Monad因为Data.Traversable中有对应的函数, sequenceA它的类型比 Applicative f => [f a] -> f [a] 稍微通用.这应该是一个明确的指标, Monad不是唯一的排序方式 .

    同样,我们可以定义foreverA如下
    foreverA :: Applicative f => f a -> f b
    foreverA f = flip const <$> f <*> foreverA f
    

    所以有更多的方法来排序非 Monad类型。但是我们遇到了foldM 的麻烦。
    foldM             :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a
    foldM _ a []      =  return a
    foldM f a (x:xs)  =  f a x >>= \fax -> foldM f fax xs
    

    如果我们尝试将这个定义翻译成 Applicative我们可能会写的风格
    foldA             :: (Applicative f) => (a -> b -> f a) -> a -> [b] -> f a
    foldA _ a []      =  pure a
    foldA f a (x:xs)  = foldA f <$> f a x <*> xs
    

    但是 Haskell 会理所当然地提示这不会进行类型检查——每次递归调用 foldA试图放置 f 的另一个“层”结果上。与 Monad我们可以 join那些层向下,但是Applicative太弱了。

    那么这如何转化为 Applicative限制我们选择运行时?嗯,这正是我们用 foldM 表达的意思。 ,一元计算(a -> b -> m a)这取决于它的a参数,来自先前一元计算的结果。这种事情在更纯粹的 Applicative 世界中根本没有任何意义。 .

    关于haskell - 'Chaining operations' 是 Monad 类解决的 "only"吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21261427/

    相关文章:

    haskell - 哪些语言实现了函数式编程的特性?

    ios - 应用函数时 Swift exc_bad_access

    haskell - 处理 IO 操作

    haskell - 如何使用foldr/foldl定义foldM(如果可能的话)?

    haskell - 与 Netwire 一起使用时对 ArrowLoop 的误解

    Haskell getContents 等待 EOF

    haskell - 在没有 `Conkin.Traversable` 的情况下将值更改为 `unsafeCoerce` 中的索引

    haskell - 如何在现实世界中使用函数式编程?

    swift - 将 [Future<Object,Error>] 转换为 Future<[Object],Error>

    haskell - 单子(monad)内的值,嵌套在数据结构中?