11

私は友人が 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"

Control.Applicative のソースにMonad インスタンスが見当たらない((->) Stringので、Control.Category または Control.Arrow を使用しているため、何かおかしなことが起こっていると思いますが、わかりません。だから私は2つの質問があると思います:

  1. これを可能にする Control.Applicative のインポートについてはどうですか?
  2. 無限ループに入るとどうなる?その場合、Haskell は実際に何を実行しようとしているのでしょうか?

ありがとう、

4

2 に答える 2

14

のインスタンスはありませんが、...(->) Stringのインスタンスがあり(->) e、そのインスタンスは多くの状況で非常に便利です。2番目の質問では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

リーダーモナドで何が起こっているのかを直感的に理解するには(知られているように)、ドキュメント、リーダーの「モナドについてのすべて」セクションを参照してください。Typeclassopedia全体に役立つヒントがいくつかあります。

于 2012-03-17T20:30:31.130 に答える
6

Control.ApplicativeをインポートControl.Monad.Instancesするため、からインスタンスを再エクスポートしますControl.Monad.Instances。これには、のインスタンスが含まFunctorMonadます((->) r)

于 2012-03-17T20:30:49.920 に答える