修补没有<< loop >>

时间:2018-12-31 15:22:26

标签: haskell tying-the-knot

上下文

我们都知道the recursively-defined Fibonacci sequence

fibs = 1 : 1 : zipWith (+) fibs (tail fibs)

λ> fibs
[1,1,2,3,5,9,13,21,34,55,89...

问题

我正在尝试在一些地方“修补”它,以便:

  1. 通用递归方程“元素是两个先前元素的和”,但是
  2. 关于单个元素的值可能有很多例外。

我在哪里

实用程序

为此,我将定义以下函数来修改列表中的特定元素:

patch :: Int -> a -> [a] -> [a]
patch i v xs = left ++ v : right where (left,_:right) = splitAt i xs

我可以用它来改变自然顺序:

λ> patch 5 0 [0..]
[0,1,2,3,4,0,6,7,8,9...

补丁发布

到目前为止,太好了。现在修补斐波那契序列:

λ> patch 1 0 fibs
[1,0,2,3,5,8,13,21,34,55,89...

这满足要求(2)。

完整补丁

同样要获得(1),我将以更明确的打结样式重写定义:

fibs' p = rec where rec = p (1 : 1 : zipWith (+) rec (tail rec))

没有补丁,它仍然可以按预期工作:

λ> fibs' id
[1,1,2,3,5,9,13,21,34,55,89...

现在我可以修补所需的元素并保留递归定义:

λ> fibs' (patch 1 0)
[1,0,1,1,2,3,5,8,13,21,34...

限制

但是我可以吗?

λ> fibs' (patch 5 0)
<<loop>>

问题

怎么了?

直觉上,数据流听起来不错。每个列表元素都应该有一个不包含循环的正确定义。我的意思是,对于无补丁fibs来说已经足够了;修补程序仅应使其定义为 more

所以我可能丢失了一些东西。我的patch函数是否存在一些严格性问题?其他地方有一些严格性问题吗?完全还有其他东西吗?

1 个答案:

答案 0 :(得分:4)

您比您想要的要严格一些。看

IN

我相信您打算保证patch i v xs = left ++ v : right where (left,_:right) = splitAt i xs 至少具有xs个元素。但是i不知道。您可能可以使用自己的分离器修复程序。

splitAt

编辑

丹尼尔·瓦格纳(Daniel Wagner)指出,您不需要splitAtGuaranteed :: Int -> [a] -> ([a], [a]) splitAtGuaranteed 0 xs = ([], xs) splitAtGuaranteed n ~(x:xs) = first (x :) $ splitAtGuaranteed (n - 1) xs 的所有惰性(或局部性)。只是一点点懒惰就足够了:

splitAtGuaranteed