2012-03-22 10 views
10

原則として、haskellの型システムは純粋なものから不純な関数(すなわちf :: a -> IO b)を呼び出すことを禁じていましたが、今日はreturnで呼び出すことによってそれらがうまくコンパイルされることに気付きました。例では:今純粋な関数内のIOアクションの意味は何ですか?

h :: Maybe() 
h = do 
    return $ putStrLn "???" 
    return() 

、多分モナドでh作品が、それにもかかわらず、純粋な機能です。実際にI/Oを実行することなく、コンパイルして実行するだけで、期待どおりにJust()が返されます。私はhaskellの怠惰は物事を一緒に入れていると思う(すなわち、putStrLnの戻り値は使用されていない - 値コンストラクタが隠されていて、それに対してパターンマッチングができないのでできない)。これを可能にする他の理由はありますか?

ボーナスとして、関連する質問:一般的に、他のものの中からモナドの行動の実行を禁止することは可能ですか?どうやって?

答えて

19

IOアクションは他のどのようなファーストクラスの値でもありません。これがHaskellのIOを表現力豊かにし、より高次の制御構造(mapM_など)を最初から構築できるようにします。怠惰はここでは関係ありません、それはあなたが実際にを実行していないことだけですアクションを実行します。あなたはちょうど値Just (putStrLn "???")を構築して、それを投げ捨てています。

putStrLn "???"既存は、画面に行を印刷しません。それ自体では、putStrLn "???"は、画面に行を印刷させるために行うことができるIOのの説明です。唯一実行されるのは、mainを実行することです。これは、他のIOアクションやGHCiに入力するアクションから構築したものです。詳細については、introduction to IOを参照してください。

実際には、IOのアクションについては、Maybeをじっくりと掘り下げたいと思うかもしれません。文字列の有効性をチェックする関数String -> Maybe (IO())があり、有効であれば、その文字列から派生した情報を出力するIOアクションを返します。これは、HaskellのファーストクラスIOアクションのために可能です。

しかし、あなたがその能力を与えなければ、モナドは別のモナドの行動を実行する能力がありません。

実際、h = putStrLn "???" `seq` return()は、任意のIOは、それがputStrLn "???"の評価を強制していても、どちらかに行われることはありません。

+0

どのようにして、モナドに含まれている値とパターンマッチングする可能性を与えることで、モナドに別のアクションを実行させることができますか? –

+3

モナドを別のモナドに変換するメソッドを作成するか、何らかの実行を行います。 'Control.Monad.ST.stToIO'は、例えば' ST'計算を 'IO'計算に変換します。 –

+0

クリスタルクリア。あなたがた両方に感謝します! –

4

desugar!今

h = do return (putStrLn "???"); return() 
-- rewrite (do foo; bar) as (foo >> do bar) 
h = return (putStrLn "???") >> do return() 
-- redundant do 
h = return (putStrLn "???") >> return() 
-- return for Maybe = Just 
h = Just (putStrLn "???") >> Just() 
-- replace (foo >> bar) with its definition, (foo >>= (\_ -> bar)) 
h = Just (putStrLn "???") >>= (\_ -> Just()) 

あなたがhを評価するとき、何が起こる?*まあ、たぶん、

(Just x) >>= f = f x 
Nothing >>= f = Nothing 

だから我々は、パターン最初のケースに私たちが実行しなければならなかったことはありませんか

f x 
-- x = (putStrLn "???"), f = (\_ -> Just()) 
(\_ -> Just()) (putStrLn "???") 
-- apply the argument and ignore it 
Just() 

お知らせと一致するためこの表現を評価するためにputStrLn "???"

* n.b。ある時点で「放棄」が止まり、「評価」が始まるところはやや不明です。コンパイラのインライン展開の決定に依存します。純粋な計算は、コンパイル時に完全に評価することができます。

+1

おかげさまでありがとうございます。新人にとって非常に便利です。私はなぜ多くのチュートリアルが砂糖で始まるのか理解していません。最初に夕食を食べ、次に砂漠があります。 – masterxilo

関連する問題