【问题标题】:Recursion error at my encode function from “99 questions in Haskell” [duplicate]“Haskell 中的 99 个问题”中的编码函数出现递归错误 [重复]
【发布时间】:2021-07-19 00:29:21
【问题描述】:

问题是:

列表的行程编码。使用problem P09的结果来实现所谓的run-length encoding数据压缩方法。元素的连续重复被编码为列表(N E),其中 N 是元素 E 的重复数。

预期结果是:

λ> encode "aaaabccaadeeee"
[(4,'a'),(1,'b'),(2,'c'),(2,'a'),(1,'d'),(4,'e')]

我已经创建了这段代码:

encode [] = []
encode (x:xs) = (counting xs,x) : encode (dropWhile (==x) xs )
 where counting (y:ys)
        | y == head ys = 1 + counting ys
        | otherwise = 0
           

repl 说:

 `<interactive>:(1,1)-(5,22): Non-exhaustive patterns in function encode`

我不知道我的递归错误在哪里。

【问题讨论】:

  • counting [] 的值应该是多少?
  • 我的思维方式有缺陷。谢谢,我意识到了我的错误,现在我在 haskell 中做得更好了。
  • 始终保持打开警告。以这种方式丢失的[] 情况由编译器在代码运行之前报告。
  • 我在 jupyter notebook 上运行 haskell,简单易学。
  • 他们可能只是想重用之前问题 9 中的函数,并使用 1) 该函数和 2) 库函数 map 解决问题 10。

标签: haskell run-length-encoding non-exhaustive-patterns


【解决方案1】:

您的代码(您的答案中的那个)基本上没问题。只需将isEmpty 替换为库函数null

只是关于优化的一点:函数encode2 扫描所有元素两次。这是因为conta 不保留第一个不同元素列表中关于位置 的信息,它只返回一个计数。

当人们用他们最喜欢的命令式语言编写这个问题时,他们当然会考虑保留一个指向列表其余部分的指针。在 Haskell 中只是稍微微妙一点,但也可以做到。

可以通过使用counta 的版本来改善这种情况,它返回计数和(指向)列表其余部分的(指针)。像这样:

-- Must return also a pointer to the rest of the input list:
extract :: Eq a => a -> Int -> [a] -> (Int, [a])
extract x0 n  []     =  (n,[])
extract x0 n (x:xs)  =  if (x==x0) then  extract x0 (n+1) xs
                                   else  (n, x:xs)

ghci下测试:

$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/  :? for help
 λ> 
 λ> :load q68434019.hs
 Ok, one module loaded.
 λ> 
 λ> extract 'a' 0 "aaaabccaadeeee"
 (4,"bccaadeeee")
 λ> 
 λ> extract 'a' 0 ""
 (0,"")
 λ> 
 λ> extract 'z' 0 "aaaabccaadeeee"
 (0,"aaaabccaadeeee")
 λ> 
 λ> extract 'z' 42 "aaaabccaadeeee"
 (42,"aaaabccaadeeee")
 λ> 

有了这个工具,使用输入列表的单次扫描就可以轻松解决问题:

encode3 :: Eq a => [a] -> [(Int,a)]
encode3  []     =  []
encode3 (x:xs)  =  let  (count, rest) = extract x 1 xs
                   in   (count, x) : (encode3 rest)

【讨论】:

    【解决方案2】:

    我是这样解决的。 conta 是计算函数。

    encode2 [] =[]
    encode2 (x:xs) = (conta x (x:xs),x) : encode2 (dropWhile (==x) xs)
     where conta y (z:zs)
            | isEmpty zs && z == y = 1
            | isEmpty zs && z /= y = 0
            | z == y = 1+ contar y (zs)
            | z /= y =0
            | otherwise = 0
           isEmpty [] = True
           isEmpty [x] = False
           isEmpty (x:xs) = False
    

    【讨论】:

    • 您的isEmpty 函数可以替换为null 库函数。
    • 如果对优化感兴趣,您可能会注意到有一个“唾手可得的果实”可能的改进:库函数dropWhile 第二次计数等于 x 的元素 b>.
    • 如果您已经在使用dropWhile,为什么不也使用takeWhile 并使用length 处理其输出。
    • 或者OP可以只使用库函数span而不是dropWhiletakeWhile
    猜你喜欢
    • 2021-12-31
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 2014-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多