Haskell 奇怪的(对我来说)行为
Haskell strange (to me) behavior
我正在解决 Haskell (https://wiki.haskell.org/99_questions/1_to_10) 的 99 个问题
,我对问题 # 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.
我已经用 foldr 函数成功解决了这个问题。
compress :: Eq e => [e] -> [e]
compress = let f v [] = [v]
f v acc
| head acc == v = acc
| otherwise = v:acc
in foldr f []
但是当我尝试像这样用递归解决同样的问题时:
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 []
我看到了非常奇怪的行为。我看到这个函数的结果:
compress' "aaaabccaadeeee"
"aaaabcabcaabcadeabcadeabcadeabcade"
但是如果我在第
行添加断点
compress' = let f acc [] = acc
它给了我正确的结果:
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>
我觉得这与 Haskell 懒惰有关....这是我最好的假设。
任何人都可以解释为什么我在执行期间会得到这个奇怪的结果,而在使用断点执行期间会得到正确的结果吗?
问题来自以下表达式:
x == last acc = acc ++ f acc xs
不需要在结果的开头附加acc
字符串,所以更正应该是:
x == last acc = f acc xs
注意acc
包含了你想要的正确结果,即没有连续重复的字符串,因此你可以在输入列表为[=15的断点处看到正确的结果acc :: [Char] = "abcade"
=].但是当它returns时,它把前面的结果合并为acc ++ "abcade"
,从中得到"aaaabcabcaabcadeabcadeabcadeabcade"
末尾的"abcade"
我正在解决 Haskell (https://wiki.haskell.org/99_questions/1_to_10) 的 99 个问题 ,我对问题 # 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.
我已经用 foldr 函数成功解决了这个问题。
compress :: Eq e => [e] -> [e]
compress = let f v [] = [v]
f v acc
| head acc == v = acc
| otherwise = v:acc
in foldr f []
但是当我尝试像这样用递归解决同样的问题时:
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 []
我看到了非常奇怪的行为。我看到这个函数的结果:
compress' "aaaabccaadeeee"
"aaaabcabcaabcadeabcadeabcadeabcade"
但是如果我在第
行添加断点compress' = let f acc [] = acc
它给了我正确的结果:
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>
我觉得这与 Haskell 懒惰有关....这是我最好的假设。 任何人都可以解释为什么我在执行期间会得到这个奇怪的结果,而在使用断点执行期间会得到正确的结果吗?
问题来自以下表达式:
x == last acc = acc ++ f acc xs
不需要在结果的开头附加acc
字符串,所以更正应该是:
x == last acc = f acc xs
注意acc
包含了你想要的正确结果,即没有连续重复的字符串,因此你可以在输入列表为[=15的断点处看到正确的结果acc :: [Char] = "abcade"
=].但是当它returns时,它把前面的结果合并为acc ++ "abcade"
,从中得到"aaaabcabcaabcadeabcadeabcadeabcade"