【发布时间】:2015-11-17 23:00:32
【问题描述】:
我试图通过以下函数来理解我所看到的内容。不确定我的理解是否不正确,或者这是 Haskell 的 GHC 实现特有的行为。
countNumLastChar :: Eq a => [a] -> (a, Int)
countNumLastChar [x] = (x, 1)
countNumLastChar (x:xs) = if x == fst y
then (fst y, (snd y) + 1)
else y
where y = countNumLastChar xs
我看到了一些我无法用这段代码解释的东西。
*Main> countNumLastChar "aba"
('a',2)
*Main> countNumLastChar "abql;kejrqlwkjer;lqwkejr;lwjerca"
('a',2)
*Main> countNumLastChar "abql;kejrqlwkjer;lqwkejr;lwjercap"
('p',1)
*Main> countNumLastChar "abql;kejrqlwkjer;lqwkejr;lwjerca;"
(';',4)
例如:使用 GHCI 跟踪下面的运行,我看到当我们到达带有尚未重复的元素的单例列表时,我们不会递归每一步。
*Main> countNumLastChar "aabc"
('c',1)
[maxOccurCharInStr.hs:(3,28)-(5,34)] *Main> :step
Stopped at maxOccurCharInStr.hs:3:31-40
_result :: Bool = _
x :: Char = 'b'
y :: (Char, Int) = _
[maxOccurCharInStr.hs:3:31-40] *Main> :list
2 countNumLastChar [x] = (x, 1)
3 countNumLastChar (x:xs) = if x == fst y
4 then (fst y, (snd y) + 1)
[maxOccurCharInStr.hs:3:31-40] *Main> :step
Stopped at maxOccurCharInStr.hs:3:36-40
_result :: a = _
y :: (a, Int) = _
[maxOccurCharInStr.hs:3:36-40] *Main> :step
Stopped at maxOccurCharInStr.hs:6:39-57
_result :: (Char, Int) = _
xs :: [Char] = 'c' : _
[maxOccurCharInStr.hs:6:39-57] *Main> :list
5 else y
6 where y = countNumLastChar xs
7
[maxOccurCharInStr.hs:6:39-57] *Main> :step
Stopped at maxOccurCharInStr.hs:(2,1)-(6,57)
_result :: (a, Int) = _
[maxOccurCharInStr.hs:(2,1)-(6,57)] *Main> :list
1 countNumLastChar :: Eq a => [a] -> (a, Int)
2 countNumLastChar [x] = (x, 1)
3 countNumLastChar (x:xs) = if x == fst y
4 then (fst y, (snd y) + 1)
5 else y
6 where y = countNumLastChar xs
7
[maxOccurCharInStr.hs:(2,1)-(6,57)] *Main> :step
Stopped at maxOccurCharInStr.hs:2:29-34
_result :: (Char, Int) = _
x :: Char = 'c'
[maxOccurCharInStr.hs:2:29-34] *Main> :list
1 countNumLastChar :: Eq a => [a] -> (a, Int)
2 countNumLastChar [x] = (x, 1)
3 countNumLastChar (x:xs) = if x == fst y
[maxOccurCharInStr.hs:2:29-34] *Main> :step
('c',1)
*Main>
我原以为最后一个 :step 会将我带回到定义中的 else y 案例,但我看到结果立即返回。但是,当最后一个字符出现之前,我们递归回来并执行(fst y, (snd y) + 1) 部分......有人可以告诉我发生了什么吗?是我的理解不正确还是 GHCI 优化了某些东西。如果是优化,它怎么知道必须直接返回结果?对此的任何参考都会有很大帮助。
【问题讨论】:
-
无法编辑 Q,因此在此继续。 IFF GHCI 正在对此进行优化,它是否被视为尾调用优化?但是如果不进行比较,在 x 和
fst y之间,GHCI 甚至调用优化是什么让我感到困惑...... -
优化不应该导致与纯代码不同的答案。在极少数情况下(当您的代码做一些不明智的事情时),它们可能会导致技术上不应该发生的异常。这不是这里的情况。你希望你的程序做什么?
-
@dfeuer:我认为程序正在做它应该做的事情。这是试图计算该列表中最后一个“char”/元素的出现次数......我试图看看这里是否有优化。如果是这样,那么该技术称为什么以及其他相关信息。
-
我没有明确的答案,但我怀疑这是因为共享、转换为连续传递样式甚至可能是尾调用消除的组合?我试图写一个简短的解释,但我觉得我对真正发生的事情没有足够的了解能够做到这一点。
-
看起来你没有到达
else y只是因为没有什么需要评估的。y已被评估,else不是表达式。