嗨,我有以下代码:
let f n (xs) = if n < 0 then f (n-1) (n:xs) else xs
f (-3) [] !! 1
我希望它能打印-4
但是它不打印任何内容,并且将计算保留在后台。
我的代码有什么问题?
答案 0 :(得分:10)
让我们逐步进行评估:
f (-3) []
f (-4) [-3]
f (-5) [-4, -3]
f (-6) [-5, -4, -3]
f (-7) [-6, -5, -4, -3]
...
考虑到这一点,您期望f (-3) [] !! 1
是什么?索引1
中的值会在每次迭代中更改,因此Haskell在到达n >= 0
的非递归情况之前是永远不会知道的。
如果您从另一个方向构建列表,它将按预期工作:
let f n = if n < 0 then n : f (n - 1) else []
> f (-3) !! 1
-4
答案 1 :(得分:2)
所以这是一个假装的整数类型:
data Int2 = ... -- 2 bit signed integers [-2, -1, 0, 1]
deriving (Num, Ord, Eq, ...)
让我们想象您的函数是在Int2
值上定义的:
f :: Int2 -> [Int2] -> [Int2]
f n (xs) = if n < 0 then f (n-1) (n:xs) else xs
这很容易确定f n xs
的评估步骤:
f 1 xs = xs
f 0 xs = xs
f (-1) xs = f (-2) (-1 : xs)
f (-2) xs = f 1 (-2 : xs) -- because finite signed arithmetic wraps around
从那里我们可以计算出f n []
的全部价值:
f 1 [] = []
f 0 [] = []
f (-1) [] = f (-2) [-1] = f 1 [-2, -1] = [-2, -1]
f (-2) [] = f 1 [-2] = [-2]
每个计算出一个值,但请注意,在我们从f (-1) []
中获得列表之前,需要花费3个评估步骤。
现在看看是否可以算出f (-1) []
是在4位数字上定义的,它需要执行多少步骤。 8位? 32位? 64位?如果它使用的是Integer
,而 没有下限?
惰性不会对您有任何帮助,因为没有部分结果,只有递归调用。那是之间的区别:
lazyReplicate 0 _ = []
lazyReplicate n x = x : lazyReplicate (n - 1) x
和
strictReplicate n x = helper [] n x where
helper xs 0 _ = xs
helper xs n x = helper (x : xs) n x