Haskell奇怪(对我而言)行为

Pav*_*vel 1 haskell computation

我正在研究Haskell的99个问题(https://wiki.haskell.org/99_questions/1_to_10),我对问题#8有疑问.

8 Problem 8
(**) Eliminate consecutive duplicates of list elements.

If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed.
Run Code Online (Sandbox Code Playgroud)

我用foldr函数成功解决了这个问题.

compress :: Eq e => [e] -> [e]
compress =  let f v [] = [v]
                f v acc 
                        | head acc == v = acc
                        | otherwise = v:acc
            in foldr f []
Run Code Online (Sandbox Code Playgroud)

但是当我尝试用这样的递归解决同样的问题时:

compress' :: Eq e => [e] -> [e]
compress' = let f acc [] = acc
                f [] (x:xs) = f [x] xs
                f acc (x:xs) | x == last acc = acc ++ f acc xs
                             | otherwise = f (acc ++ [x]) xs 
            in f []
Run Code Online (Sandbox Code Playgroud)

我觉得这很奇怪.我看到这个函数的结果:

compress' "aaaabccaadeeee"
"aaaabcabcaabcadeabcadeabcadeabcade"
Run Code Online (Sandbox Code Playgroud)

但是如果我在线上添加断点

compress' = let f acc [] = acc
Run Code Online (Sandbox Code Playgroud)

它给了我正确的结果:

ghci> compress' "aaaabccaadeeee"
"aaaabcabcaabcadeabcadeabcadeabcade"
ghci> :break 304
Breakpoint 7 activated at haskell-tut.hs:304:28-30
ghci> compress' "aaaabccaadeeee"
"aaaabcabcaabcadeabcadeabcadeStopped in Main.compress'.f, haskell-tut.hs:304:28-30
_result :: [Char] = _
acc :: [Char] = "abcade"
[haskell-tut.hs:304:28-30] ghci> :con
abcade"
ghci>
Run Code Online (Sandbox Code Playgroud)

我觉得这是关于Haskell懒惰的一些事情......这是我最好的假设.任何人都可以解释为什么我在执行期间得到这个奇怪的结果并在执行断点期间得到正确的结果?

ass*_*.jc 5

问题来自下面的表达式:

x == last acc = acc ++ f acc xs
Run Code Online (Sandbox Code Playgroud)

它不需要acc在结果的开头附加字符串,因此更正应该是:

x == last acc = f acc xs
Run Code Online (Sandbox Code Playgroud)

请注意,acc包含所需的正确结果,即没有连续重复的字符串,因此您可以acc :: [Char] = "abcade"在输入列表的断点处看到正确的结果[].但是当它返回时,它结合了之前的结果acc ++ "abcade",从中结束了"abcade""aaaabcabcaabcadeabcadeabcadeabcade"

  • @Pavel我不确定`:continue`是如何工作的,但它似乎打印出`_result`变量,该变量与特定断点有关,而不是函数的最终结果.如果你试图将断点设置为`f []`中的行,并尝试`:countinue`命令,它将打印`aaaabcabcaabcadeabcadeabcadeabcade"`而不是`abcade"` (2认同)