haskell - 为什么导入 Control.Applicative 允许此错误代码进行类型检查?

标签 haskell applicative

我正在帮助一个 friend 学习 Haskell,他最近创建了这样的代码,该代码在运行时检查并产生 CPU 燃烧循环。我对此完全感到困惑。

import Control.Monad
import Control.Applicative

main = forever putStrLn "Hello, infinity"

那不应该类型检查,但确实如此。正确的版本显然是:
main = forever $ putStrLn "Hello, infinity"

令我感到奇怪和惊讶的是,无论是否导入 Control.Applicative,您都会得到不同的结果。如果不导入它,它不会输入检查:
Prelude Control.Monad> forever putStrLn "Hello, infinity"

<interactive>:1:1:
    No instance for (Monad ((->) String))
      arising from a use of `forever'
    Possible fix: add an instance declaration for (Monad ((->) String))
    In the expression: forever putStrLn "Hello, infinity"
    In an equation for `it': it = forever putStrLn "Hello, infinity"

我没有看到 ((->) String 的 Monad 实例在 Control.Applicative 的源代码中,所以我猜测由于它使用 Control.Category 或 Control.Arrow 正在发生一些奇怪的事情,但我不知道。所以我想我有两个问题:
  • 导入 Control.Applicative 的原因是什么?
  • 当它进入无限循环时会发生什么?在这种情况下,Haskell 实际上试图执行什么?

  • 谢谢,

    最佳答案

    没有 (->) String 的实例,但有 (->) e 的实例……这个例子在很多情况下都非常非常有用。对于第二个问题,我们必须看看forever和函数的类实例:

    instance Monad ((->) e) where
        return x = \e -> x
        m >>= f  = \e -> f (m e) e
    
    forever m = m >> forever m = m >>= \_ -> forever m
    

    现在,forever putStrLn 是什么意思?做?
    forever putStrLn
        = putStrLn >>= \_ -> forever putStrLn
        = \e -> (\_ -> forever putStrLn) (putStrLn e) e
        = \e -> (forever putStrLn) e
        = forever putStrLn
    

    ...它只是一个纯粹的无限循环,基本等同于loop = loop .

    要了解阅读器 monad(众所周知)的情况,请查看 the documentation ,关于单子(monad)的一切section on Reader ,并且在整个 Typeclassopedia 中散布着一些提示。这可能会有所帮助。

    关于haskell - 为什么导入 Control.Applicative 允许此错误代码进行类型检查?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9753389/

    相关文章:

    haskell - 嵌套类型级编程

    haskell - Haskell 的reactive-banana 中的reactive-web 的flatMap 相当于什么?

    haskell - 编写应用程序

    haskell - `sequenceA` 的工作原理

    Yesod/Persistent 的 MongoDB 示例

    haskell - 自动将功能应用于子结构

    function - 编程 * 仅使用 succ 和 pred

    haskell - 如何证明单子(monad)是一个仿函数和一个应用仿函数?

    haskell - 如何将可选标志解析为 Maybe 值?

    haskell - Traversable is to Applicative contexts 是什么意思?