如何比较Haskell中的两个文件

时间:2016-05-20 17:52:45

标签: haskell functional-programming

我正在学习Haskell,我需要比较两个文件。 我没有找到这样做的函数,所以我自己编写了它。以下是我提出的功能。

cmpFiles :: FilePath -> FilePath -> IO Bool
cmpFiles a b = withBinaryFile a ReadMode $ \ha ->
               withBinaryFile b ReadMode $ \hb ->
                 fix (\loop -> do
                   isEofA <- hIsEOF ha
                   isEofB <- hIsEOF hb

                   if | isEofA && isEofB -> return True             -- both files reached EOF
                      | isEofA || isEofB -> return False            -- only one reached EOF
                      | otherwise        -> do                      -- read content
                                              x <- hGet ha 4028     -- TODO: How to use a constant?
                                              y <- hGet hb 4028     -- TODO: How to use a constant?
                                              if x /= y
                                                then return False   -- different content
                                                else loop           -- same content, contunue...
                 )

我的问题是:

  1. 这段代码是不是惯用的?它看起来非常紧迫而不是功能性。
  2. 此代码是否有效(Layz IO问题大文件,性能......)?
  3. 是否有更紧凑的方式来编写它?

2 个答案:

答案 0 :(得分:6)

怎么样

cmpFiles a b = do
    aContents <- readFile a
    bContents <- readFile b
    return (aContents == bContents)

答案 1 :(得分:0)

你甚至可以用它做一个单行:

cmpFiles a b = liftM2 (==) (readFile a) (readFile b)

这个实际上相当于Reid Barton的解决方案。如果您从hackage

中选择liftM2的定义,那么等效不是狡猾的词
liftM2 f m1 m2 = do { x1 <- m1; x2 <- m2; return (f x1 x2) }

并立即插入(==)readFile

懒惰是你在haskell的朋友。 The documentation of readFile表示输入是 lazily ,即仅按需读取。 ==也很懒惰。因此,整个liftM22 ...只读取文件,直到找到差异。