6

これは初心者の質問です。

おそらく次のような、画像の遅延ストリームを提供する関数を書きたいと思います。

imageStream :: [IO Image]

残念ながら、画像を読み取る関数は失敗する可能性があるため、次のようになります。

readImage :: IO (Maybe Image)

したがって、私書くことができる関数は次のようになります。

maybeImageStream :: [IO (Maybe Image)]

遅延 IO を維持しながら、次のような関数を実装するにはどうすればよいですか?

flattenImageStream :: [IO (Maybe Image)] -> [IO Image]

意味的にflattenImageStreamは、次の画像を要求すると、リストを反復処理して各画像を読み取ろうとする必要があります。ロードする画像が見つかるまでこれを行い、それを返します。

編集:答えにはいくつかの意見の相違があるようです。を使用するソリューションを提案している人もいますがsequence、それをテストしたところ、怠惰を破壊することがわかったと確信しています。(コンピューターに戻ったときにもう一度テストして確認します。)unsafeInterleaveIO. その関数のドキュメントから、うまくいくように見えますが、型システムを可能な限り尊重したいのは明らかです。

4

4 に答える 4

9

ListTfromを使用できます。これは、この場合に正しいことを行うpipeslazy のより安全な代替手段を提供します。IO

失敗する可能性のある画像の遅延ストリームをモデル化する方法は次のとおりです。

imageStream :: ListT IO (Maybe Image)

次のタイプの画像読み込み機能があると仮定します。

loadImage :: FileName -> IO (Maybe Image)

..そのようなストリームを構築する方法は次のようになります。

imageStream = do
    fileName <- Select $ each ["file1.jpg", "file2.jpg", "file3.jpg"]
    lift $ loadImage fileName

dirstreamライブラリを使用すると、ディレクトリの内容を遅延ストリーミングすることもできます。

成功した結果のみを除外する関数には、次のタイプがあります。

flattenImageStream :: (Monad m) => ListT m (Maybe a) -> ListT m a
flattenImageStream stream = do
    ma <- stream
    case ma of
        Just a  -> return a
        Nothing -> mzero

この関数は、任意の基本モナドに対して機能することに注意してくださいm。それについて特定のものは何もありませんIO。怠惰も保ちます!

に適用するflattenImageimageStream、次のようなものが得られます。

finalStream :: List IO Image
finalStream = flattenImage imageStream

次に、これらの画像を使用する次のタイプの関数があるとします。

useImage :: Image -> IO ()

関数ListTを使用してファイナルを処理する場合は、次のように記述します。useImage

main = runEffect $
    for (every finalStream) $ \image -> do
        lift $ useImage image

これにより、画像ストリームが遅延して消費されます。

もちろん、コード ゴルフをプレイして、そのすべてを次のはるかに短いバージョンに結合することもできます。

main = runEffect $ for (every image) (lift . useImage)
  where
    image = do
        fileName   <- Select $ each ["file1.jpg", "file2.jpg", "file3.jpg"]
        maybeImage <- lift $ loadImage fileName           
        case maybeImage of
            Just img -> return img
            Nothing  -> mzero

failの定義を追加して、次のListTように書けるようにすることも考えています。

main = runEffect $ for (every image) (lift . useImage)
  where
    image = do
        fileName <- Select $ each ["file1.jpg", "file2.jpg", "file3.jpg"]
        Just img <- lift $ loadImage fileName           
        return img
于 2013-11-01T22:18:43.330 に答える
1

提案されているように、シーケンスを使用して [ma] を m [a] に変換できます

だからあなたは得る:

imageStream :: IO [Image]

次に、Data.Maybe の cayMaybes を使用して、Just 値のみを保持できます。

catMaybes `liftM` imageStream
于 2013-11-01T21:09:54.130 に答える
0

これを要求どおりに実装するには、IO モナドの外側で IO 内の値が であったかどうかを知る必要があるように思われますNothing。また、IO はその値が外部の純粋に機能的な世界に「漏れる」ことを防ぐように設計されているため (unsafePerformIOにもかかわらず)、これは不可能です。 . 代わりに、IO [Image]:を生成しsequenceて を に変換し[IO (Maybe Image)]IO [Maybe Image]次にData.Maybe.catMaybesIO モナド内で (たとえばfmaporと一緒にliftM) を使用して に変換することをお勧めしますIO [Image]

flattenImageStream = fmap catMaybes $ sequence maybeImageStream
于 2013-11-01T21:08:44.023 に答える