2012-03-17 42 views
10

我正在帮助朋友学习Haskell,他最近创建了类似这样的代码,该类型在运行时检查并生成CPU烧录循环。我完全被这个困惑了。为什么导入Control.Applicative允许这个错误的代码类型检查?

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单子实例在源Control.Applicative,所以我猜奇怪的事情正在发生,由于其使用的Control.Category或Control.Arrow,但我不知道。所以我想我有两个问题:

  1. 什么是导入Control.Applicative,让这种情况发生?
  2. 进入无限循环时发生了什么?在这种情况下,Haskell实际上试图执行什么?

感谢,

回答

13

没有为(->) 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相同。

为了得到一些直觉这是怎么回事与读者单子(因为它是已知的),看看the documentation,所有关于单子section on Reader,还有整个Typeclassopedia这可能有助于洒一些提示。

+0

您能否详细说明'( - >)e'的实例对于什么有用? – 2012-03-17 20:37:55

+4

@DanielLyons当您有许多功能都需要访问某些共享的配置信息时,它非常有用。然后你可以写(例如)'foo >> = bar >> = baz',而不是像'\ e - > let x = foo e; y = bar x e; z = baz y e in y'。 – 2012-03-17 21:08:50

6

Control.Applicative进口Control.Monad.Instances,因此从Control.Monad.Instances重新导出实例。这包括((->) r)FunctorMonad实例。

相关问题