我一直在解决一个非常简单的问题:生成所有长度为 的递减序列,由按字典顺序从到L
的自然数组成。然而,我遇到了一个非常奇怪的问题。看一看:1
M
c :: (Ord a, Num a, Enum a) => a -> a -> [[a]]
c m 1 = map return [1..m]
c m l = do
n <- [l..m]
res <- c (n - 1) (l - 1)
return $ n:res
c' :: (Ord a, Num a, Enum a) => a -> a -> [[a]]
c' m = helper 1 m where
helper :: (Ord a, Num a, Enum a) => a -> a -> a -> [[a]]
helper a b 1 = map return [a..b]
helper a b l = do
n <- [a..b]
True <- return $ (l - 1 <= n)
res <- helper a (n - 1) (l - 1)
return (n:res)
所以,很明显,这两个函数做的事情完全一样(我在许多测试中检查了它们,它们都给出了正确的结果),但是如果你尝试在 GHCi 中进行评估c 100 98
,c' 100 98
你会发现它在时间上的巨大差异需要:
[a..b]
所以,我对每次生成都有点不安,但我做了一点询问,有人建议 Haskell 不会立即进行模式匹配,而是由于惰性评估而延迟了它,这导致大量额外调用c'
. 然而,第二个理论并不完全成立:我直接在 GHCi 命令提示符下在我的代码中设置了一个断点来监视 的值n
,这表明延迟模式匹配并非如此。
问题实际上可能出在enumFromTo
功能上,还是有其他原因?