Haskell Lempel Ziv 78压缩

时间:2015-06-13 13:59:36

标签: haskell

http://pl.wikipedia.org/wiki/LZ78 这是一个波兰维基百科网站,但它包含一个python代码,可用于检查haskell代码是否有效

我使用示例中的文字: abbbcaabbcbbcaaac

我的问题是,当trace以正确的顺序显示char / int对时,它们会以某种方式在输出列表中混乱。有人可以解释一下发生了什么吗?

这是正确的顺序: (0,A) (0,b)中 (2,B) (0,c)中 (1,A) (3,c)中 (参照图6,) (5,c)中

import System.IO  
import Control.Monad
import qualified Data.Map as Map
import Debug.Trace
main = do  
  contents <- readFile "file.txt"    
  print $ compress contents Map.empty 1 "" []
compress :: String -> Map.Map String Int -> Int -> String -> [(Int,Char)]-> [(Int,Char)]
compress (s:x) m i c out = do
    if Map.member (c++[s]) m == False 
        then do 
            if c == ""
                then do
                    let newMap = trace( show s ++ "  0  aaaaaa\n") Map.insert [s] i m
                    compress x newMap (i+1) c (out++[(0,s)])
                else do
                    let newMap = trace(show s ++ "  " ++ show (m Map.! c) ++ "  bbbbb\n") Map.insert (c++[s]) i m
                    compress x newMap (i+1) "" out++[(newMap Map.! c, s)]
        else compress x m i (c++[s]) out

compress s m i c out = compress2 out

compress2 ::  [(Int,Char)]-> [(Int,Char)]
compress2 out = out

1 个答案:

答案 0 :(得分:2)

这是一个括号错误:

compress x newMap (i+1) "" out++[(newMap Map.! c, s)]

解析为

(compress x newMap (i+1) "" out) ++ [(newMap Map.! c, s)]

但你想要

compress x newMap (i+1) "" (out++[(newMap Map.! c, s)])
顺便说一句,有趣的问题。我尝试重写你的代码,使其更加惯用:

import System.IO
import Data.Map as M
import Prelude as P

main = do
  contents <- readFile "file.txt"
  print $ compress contents

compress :: String -> [(Int, Char)]
compress = reverse . third . P.foldl step (singleton "" 0, "", [])
  where step (dict, pat, log) char =
          let pat' = char:pat
          in if member pat' dict
            -- `pat'` is already in our dictionary, so
            -- we've previously extended `pat` by `char`, and 
            -- we don't need to record anything
            then (dict, pat', log)
            -- pat' is new to us, so 
            --  * assign it a new id in the dictionary 
            --  * start reading a new pattern
            --  * record it in the log
            else (insert pat' (size dict) dict, "", (dict ! pat, char):log)
        third (_, _, log) = log