簡體   English   中英

懶惰地評估Haskell中的monadic函數

[英]Lazily evaluate monadic functions in Haskell

我似乎無法弄清楚我遇到的這個問題的解決方法。

我有這樣的事情:

  getFilePathForDay :: Day -> IO (Maybe FilePath)

  getFilePathForDays date days = do
      files <- mapM getFilePathForDay $ iterate (addDays 1) date
      return . take days . catMaybes $ files

我試圖得到x個有效的文件路徑,其中x是我想要的天數,但上面的代碼只是永遠運行。 我在使用monads時遇到過這個問題,我想知道是否有一個解決方法可用於我遇到的這個問題。

謝謝!

代碼永遠運行,因為您試圖在調用mapM對無限多個副作用計算進行mapM

由於您catMaybes並不知道需要運行多少這些計算(如使用catMaybes ),因此必須將對getFilePathForDay的調用與其余計算交錯。 這可以使用unsafeInterleaveIO來完成,但顧名思義,這不是推薦的方法。

您可以手動實現:

getFilePathForDays _ 0 = return []
getFilePathForDays date days = do
    mpath <- getFilePathForDay date
    case mpath of
        Just path -> (path :) <$> remaining (days-1)
        Nothing   -> remaining days
  where
    remaining days = getFilePathForDays (addDays 1 date) days

可能有更優雅的方式,但它現在不是我的意思:)

有時懶惰的IO是正確的方法。 由於你有一個無限的,懶惰的天數序列,並且你正在從該序列中懶散地采樣一些(動態的)范圍,我們也應該只按需命中文件系統。

這可以使用unsafeInterleaveIO完成:

import System.IO.Unsafe         ( unsafeInterleaveIO )

-- return a lazy list of filepaths, pull as many as you need
getFilePathForDays :: Day -> Int -> IO [FilePath]
getFilePathForDays date days = do

    let go (d:ds) = unsafeInterleaveIO $ do
                        f  <- getFilePathForDay d
                        fs <- go ds
                        return (f:fs)

    -- an infinite, lazy stream of filepaths
    fs <- go (iterate (addDays 1) date)

    return . take days . catMaybes $ fs

go返回一個懶惰的結果流,我們采取盡可能多的結果。 簡單。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM