3

コードを仮定します

f :: IO [Int]
f = f >>= return . (0 :)

g :: IO [Int]
g = f >>= return . take 3

gghci で実行すると、stackoverflow が発生します。[0, 0, 0]しかし、私はそれが怠惰に評価され、製品がに包まれるのではないかと考えていましたIO。ここにIO責任があると思いますが、本当にわかりません。明らかに、次のように機能します。

f' :: [Int]
f' = 0 : f'

g' :: [Int]
g' = take 3 f'

編集:実際、私はそのような単純な関数を持つことに興味がありませんf。元のコードは次のように見えました:

h :: a -> IO [Either b c]
h a = do
    (r, a') <- h' a
    case r of
        x@(Left  _) -> h a' >>= return . (x :)
        y@(Right _) -> return [y]

h' :: IO (Either b c, a)
-- something non trivial

main :: IO ()
main = mapM_ print . take 3 =<< h a

hいくつかのIO計算を行い、有効な応答 ( ) が生成さLeftれるまで無効な ( ) 応答をリストに格納します。モナドRight内にいるにもかかわらず、リストを遅延して構築しようとしています。IOの結果を読んでいる人hが、リストが完了する前であってもリストの消費を開始できるようにします (リストは無限になる可能性があるため)。そして、結果を読む人3が何があっても最初のエントリだけを気にするのであれば、残りのリストを構築する必要さえありません。そして、これは不可能だと感じています:/。

4

3 に答える 3

2

これが適切な使用法であるかどうかはわかりませんが、の内部の値が求められるまでunsafeInterleaveIOの IO アクションを延期することにより、求めている動作が得られます。ff

module Tmp where
import System.IO.Unsafe (unsafeInterleaveIO)

f :: IO [Int]
f = unsafeInterleaveIO f >>= return . (0 :)

g :: IO [Int]
g = f >>= return . take 3

*Tmp> g
[0,0,0]
于 2015-09-09T23:01:05.440 に答える