簡體   English   中英

讀取引用了Haskell中其他文件的文件

[英]reading files with references to other files in haskell

我正在嘗試使用具有對其他文件的引用的功能來擴展常規markdown,以便將引用文件中的內容呈現在“主”文件中的相應位置。

但是我最遠的是要實施

createF :: FTree -> IO String
createF Null = return ""
createF (Node f children) = ifNExists f (_id f)
                              (do childStrings <- mapM createF children
                                  withFile (_path f) ReadMode $ \handle ->
                                    do fc <- lines <$> hGetContents handle
                                       return $ merge fc childStrings)

ifNExists只是一個可以忽略的助手,真正的問題發生在讀取句柄時,它僅返回空字符串,我認為這是由於IO懶惰造成的。

我認為使用withFile filepath ReadMode $ \\handle -> {-do stutff-}hGetContents handle將是正確的解決方案,因為我已閱讀fcontent <- withFile filepath ReadMode hGetContents是一個壞主意。

令我困惑的另一件事是功能

createFT :: File -> IO FTree
createFT f = ifNExists f Null
               (withFile (_path f) ReadMode $ \handle ->
                  do let thisParse = fparse (_id f :_parents f)
                     children <-rights . map ( thisParse . trim) . lines <$> hGetContents handle
                     c <- mapM createFT children
                     return $ Node f c)

奇跡般有效。

那么為什么createF只返回一個空字符串?

整個項目和要測試的目錄/文件可以在github上找到


這是數據類型定義

type ID = String

data File = File {_id :: ID, _path :: FilePath, _parents :: [ID]}
          deriving (Show)
data FTree = Null
           | Node { _file :: File
                  , _children :: [FTree]} deriving (Show)

正如您所懷疑的,懶惰的IO可能是問題所在。 這是(糟糕的)規則,您必須遵循此規則才能正確使用它,而又不會費勁:

在完成完全評估其結果所需的所有(惰性)I / O之前, withFile計算必須完成。

如果在關閉句柄后有一些強制I / O的操作,則即使出現異常,也不能保證會出現錯誤。 而是,您得到完全未定義的行為。

您可以使用return $ merge fc childStrings破壞此規則,因為在完全評估該值之前將其返回。 相反,您可以做的是

let retVal = merge fc childStrings
deepSeq retVal $ return retVal

可以說更清潔的替代方法是將所有依賴於那些結果的其余代碼放入withFile參數中。 唯一不這樣做的真正原因是,如果您在處理完該文件之后還對結果進行了很多其他工作。 例如,如果您要處理大量不同的文件並累積它們的結果,那么在完成處理后,您一定要確保關閉每個文件。 如果您只是讀入一個文件然后對其進行操作,則可以將其打開直到完成。


順便說一句,我剛剛向GHC團隊提交了功能請求 ,以查看他們是否願意使此類程序更可能因有用的錯誤消息而更早地失敗。


更新

功能請求已被接受,這樣的程序現在更有可能產生有用的錯誤消息。 請參閱什么原因導致此“關閉的句柄讀取延遲”錯誤? 有關詳細信息。

我強烈建議您避免使用惰性IO,因為它總是會產生這樣的問題,如惰性I / O有何缺點? 就像您的情況一樣,您需要保持文件打開狀態直到其被完全讀取為止,但這意味着在實際消耗內容時,要用純代碼在某個位置關閉文件。

一種可能性是使用嚴格的ByteString並使用readFile讀取文件。 這也將使許多操作更有效。

另一個選擇是使用一個解決延遲IO問題的庫(請參閱枚舉器與管道,管道的優缺點是什么? )。 這些庫使您可以將內容生產與其處理或消費分開。 因此,您可以有一個讀取輸入文件並生成一些令牌流的生產者,以及一個使用該流並產生一些結果的純使用者(不取決於IO )。 例如,在多余管道中,有一個模塊atto-parsec解析器轉換為使用者。 另請參見是否有更好的方式遍歷目錄樹?

暫無
暫無

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

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