使用scanl和自引用列表的斐波那契数列

时间:2018-07-02 08:26:42

标签: haskell

我正在通过Chris Allen Haskell编程书来学习Haskell。我被困在使用scanl和自引用列表定义Fibonacci系列的一部分上。 我了解对以下代码的评估:

scanl (+) 1 [1..3]
1 : (scanl (+) ((+) 1 1) [2,3])

我读到(+)在两个参数上都是严格的,因此下一步将((+)1 1)替换为2。

1 : (2 : (scanl (+) ((+) 2 2) [3]))
1 : (2 : (4 : (scanl (+) ((+) 4 3) [])))
1 : (2 : (4 : (7 : (scanl (+) 7 []))))
1 : (2 : (4 : (7 : [])))

我无法理解以下代码的评估以及它如何产生正确的斐波那契数列。

fibs = 1 : scanl (+) 1 fibs.

我很难找到非空列表(x:xs)的模式匹配如何用于自引用列表。 感谢帮助和任何资源,以更好地了解自引用/无限列表。

1 个答案:

答案 0 :(得分:2)

我们可以使用由1:引起的相位差来仅使用scanl进行递归后向引用,如您在上一个示例中所示。

let fib = 1 : scanl (+) 1 fib in take 5 fib

以这种形式替换scanl的定义时,我们首先看到(x:xs)与现有的:相匹配:

1 : 1 : scanl (+) 2 (drop 1 fibs)

此时,第二个元素存在,因此我们可以提取另一个x

1 : 1 : 2 : scanl (+) 3 (drop 2 fibs)
1 : 1 : 2 : 3 : scanl (+) 5 (drop 3 fibs)
1 : 1 : 2 : 3 : 5 : scanl (+) 8 (drop 4 fibs)

我们并不是真正使用drop,而是通过为每个元素匹配:来沿着我们正在构建的相同列表前进。我必须给其余列表命名,以递归地引用它,并发现drop形式可以方便地表示生成和起源。实际上,像这样使用drop会使整个列表保留在内存中,并从头开始遍历不必要的遍历以查找下一个元素。实际上,只有小块形状像递归let表达式那样作为尾巴,直到我们对其求值:

fibsfrom a b = let morefibs = a : scanl (+) b morefibs in morefibs

如果将此函数以1 1或其他任意位置作为种子,则可以通过连续的一对斐波那契数对种子来获得整个列表。尝试使用例如2 3或5 8.尾巴的公式先回到列表的前一个元素,因此可以始终将其拆分为头尾。

有时将引用作为图形查看会更清楚。我们将递归视为一个循环,但是仍然可以进行评估,因为我们只需要head list即可执行下一步。这是前几个步骤的graphviz点渲染(为回旋处的“运行代码段-全页”方法表示歉意,堆栈溢出无法整齐地处理点或svg)。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg  PUBLIC '-//W3C//DTD SVG 1.1//EN'  'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
<svg width="667pt" height="392pt" viewBox="0 0 666.59 392" xmlns="http://www.w3.org/2000/svg"><g id="a" class="graph" transform="scale(1) translate(4 388)"><title>fibs</title><polygon points="-4 4 -4 -388 662.59 -388 662.59 4" fill="#fff" stroke="transparent"/><g id="b" class="node"><title>fibs</title><ellipse cx="78" cy="-366" rx="46.292" ry="18" fill="none" stroke="#000"/><text x="78" y="-362.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">head : tail</text></g><g id="c" class="node"><title>1</title><ellipse cx="27" cy="-192" rx="27" ry="18" fill="none" stroke="#000"/><text x="27" y="-188.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">1</text></g><g id="d" class="edge"><title>fibs-&gt;1</title><path d="m56.935-349.84c-14.569 12.593-32.75 31.487-40.935 52.841-9.6269 25.117-4.6011 55.944 1.4413 77.679" fill="none" stroke="#000"/><polygon points="20.795 -220.32 20.334 -209.74 14.094 -218.3" stroke="#000"/><text x="29" y="-275.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">head</text></g><g id="e" class="node"><title>scanl</title><ellipse cx="119" cy="-279" rx="67.688" ry="18" fill="none" stroke="#000"/><text x="119" y="-275.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">scanl op init list</text></g><g id="f" class="edge"><title>fibs-&gt;scanl</title><path d="m74.923-347.75c-0.8767 10.092-0.562 22.605 4.0774 32.753 1.9313 4.2246 4.6212 8.1661 7.7022 11.775" fill="none" stroke="#000"/><polygon points="89.414 -305.46 93.929 -295.87 84.422 -300.55" stroke="#000"/><text x="88" y="-318.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">tail</text></g><g id="g" class="edge"><title>scanl-&gt;fibs</title><path d="m111.6-297.09c-4.1167-9.8196-9.4396-22.122-14.602-32.907-1.4341-2.996-2.982-6.1053-4.5537-9.1854" fill="none" stroke="#000"/><polygon points="89.269 -337.71 87.75 -348.2 95.476 -340.95" stroke="#000"/><text x="112.5" y="-318.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">list</text></g><g id="h" class="edge"><title>scanl-&gt;1</title><path d="m100.38-261.39c-14.397 13.615-34.421 32.55-49.915 47.202" fill="none" stroke="#000"/><polygon points="52.502 -211.3 42.832 -206.97 47.693 -216.39" stroke="#000"/><text x="88.5" y="-231.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">init</text></g><g id="i" class="node"><title>+</title><ellipse cx="119" cy="-192" rx="27" ry="18" fill="none" stroke="#000"/><text x="119" y="-188.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">+</text></g><g id="j" class="edge"><title>scanl-&gt;+</title><path d="m119-260.97v40.815" fill="none" stroke="#000"/><polygon points="122.5 -220 119 -210 115.5 -220" stroke="#000"/><text x="126" y="-231.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">op</text></g><g id="k" class="node"><title>g1fibs</title><ellipse cx="254" cy="-366" rx="46.292" ry="18" fill="none" stroke="#000"/><text x="254" y="-362.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">head : tail</text></g><g id="l" class="node"><title>g1_1</title><ellipse cx="226" cy="-192" rx="27" ry="18" fill="none" stroke="#000"/><text x="226" y="-188.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">1</text></g><g id="m" class="edge"><title>g1fibs-&gt;g1_1</title><path d="m246.94-348.16c-5.1005 13.748-11.65 33.355-14.942 51.158-4.7502 25.686-6.065 55.455-6.3006 76.722" fill="none" stroke="#000"/><polygon points="229.2 -219.99 225.66 -210 222.2 -220.01" stroke="#000"/><text x="245" y="-275.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">head</text></g><g id="n" class="node"><title>g1fibs1</title><ellipse cx="313" cy="-279" rx="46.292" ry="18" fill="none" stroke="#000"/><text x="313" y="-275.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">head : tail</text></g><g id="o" class="edge"><title>g1fibs-&gt;g1fibs1</title><path d="m265.94-348.39c8.4769 12.5 19.995 29.485 29.515 43.522" fill="none" stroke="#000"/><polygon points="298.36 -306.82 301.08 -296.58 292.57 -302.89" stroke="#000"/><text x="297" y="-318.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">tail</text></g><g id="p" class="edge"><title>g1fibs1-&gt;g1_1</title><path d="m296.23-262.23-47.89 47.89" fill="none" stroke="#000"/><polygon points="250.53 -211.58 240.98 -206.98 245.58 -216.53" stroke="#000"/><text x="288" y="-231.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">head</text></g><g id="q" class="node"><title>g1scanl</title><ellipse cx="346" cy="-192" rx="67.688" ry="18" fill="none" stroke="#000"/><text x="346" y="-188.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">scanl op init list</text></g><g id="r" class="edge"><title>g1fibs1-&gt;g1scanl</title><path d="m308.16-260.89c-1.7731 10.049-2.433 22.565 1.8437 32.89 1.6363 3.9503 3.9396 7.6932 6.5995 11.166" fill="none" stroke="#000"/><polygon points="319.3 -219.06 323.31 -209.25 314.06 -214.42" stroke="#000"/><text x="319" y="-231.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">tail</text></g><g id="s" class="edge"><title>g1scanl-&gt;g1fibs1</title><path d="m339.91-210.03c-3.379-9.8004-7.7327-22.106-11.911-32.973-1.1063-2.8775-2.2936-5.8702-3.498-8.8462" fill="none" stroke="#000"/><polygon points="321.25 -250.55 320.67 -261.13 327.72 -253.22" stroke="#000"/><text x="342.5" y="-231.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">list</text></g><g id="t" class="node"><title>g1+</title><ellipse cx="304" cy="-105" rx="27" ry="18" fill="none" stroke="#000"/><text x="304" y="-101.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">+</text></g><g id="u" class="edge"><title>g1scanl-&gt;g1+</title><path d="m337.3-173.97c-5.9348 12.293-13.893 28.778-20.541 42.549" fill="none" stroke="#000"/><polygon points="319.9 -129.89 312.4 -122.41 313.6 -132.94" stroke="#000"/><text x="335" y="-144.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">op</text></g><g id="v" class="node"><title>2</title><ellipse cx="376" cy="-105" rx="27" ry="18" fill="none" stroke="#000"/><text x="376" y="-101.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">2</text></g><g id="w" class="edge"><title>g1scanl-&gt;2</title><path d="m352.22-173.97c4.1303 11.978 9.6324 27.934 14.304 41.482" fill="none" stroke="#000"/><polygon points="369.94 -133.3 369.89 -122.71 363.33 -131.02" stroke="#000"/><text x="372.5" y="-144.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">init</text></g><g id="x" class="node"><title>g2fibs</title><ellipse cx="490" cy="-366" rx="46.292" ry="18" fill="none" stroke="#000"/><text x="490" y="-362.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">head : tail</text></g><g id="y" class="node"><title>g2_1</title><ellipse cx="459" cy="-192" rx="27" ry="18" fill="none" stroke="#000"/><text x="459" y="-188.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">1</text></g><g id="z" class="edge"><title>g2fibs-&gt;g2_1</title><path d="m483.09-348.13c-5.0245 13.763-11.542 33.375-15.088 51.13-5.1251 25.668-7.3327 55.439-8.2831 76.711" fill="none" stroke="#000"/><polygon points="463.2 -219.87 459.33 -210.01 456.21 -220.13" stroke="#000"/><text x="481" y="-275.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">head</text></g><g id="aa" class="node"><title>g2fibs1</title><ellipse cx="549" cy="-279" rx="46.292" ry="18" fill="none" stroke="#000"/><text x="549" y="-275.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">head : tail</text></g><g id="ab" class="edge"><title>g2fibs-&gt;g2fibs1</title><path d="m501.94-348.39c8.4769 12.5 19.995 29.485 29.515 43.522" fill="none" stroke="#000"/><polygon points="534.36 -306.82 537.08 -296.58 528.57 -302.89" stroke="#000"/><text x="533" y="-318.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">tail</text></g><g id="ac" class="edge"><title>g2fibs1-&gt;g2_1</title><path d="m531.65-262.23c-14.093 13.624-34.094 32.957-49.542 47.89" fill="none" stroke="#000"/><polygon points="484.12 -211.41 474.5 -206.98 479.25 -216.45" stroke="#000"/><text x="523" y="-231.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">head</text></g><g id="ad" class="node"><title>g2fibs2</title><ellipse cx="550" cy="-192" rx="46.292" ry="18" fill="none" stroke="#000"/><text x="550" y="-188.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">head : tail</text></g><g id="ae" class="edge"><title>g2fibs1-&gt;g2fibs2</title><path d="m549.21-260.97c0.1354 11.782 0.3151 27.413 0.4691 40.815" fill="none" stroke="#000"/><polygon points="553.18 -220.04 549.79 -210 546.18 -219.96" stroke="#000"/><text x="559" y="-231.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">tail</text></g><g id="af" class="node"><title>g2_2</title><ellipse cx="478" cy="-105" rx="27" ry="18" fill="none" stroke="#000"/><text x="478" y="-101.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">2</text></g><g id="ag" class="edge"><title>g2fibs2-&gt;g2_2</title><path d="m534.48-174.98c-5.3072 5.9359-11.228 12.686-16.481 18.975-7.1414 8.55-14.742 18.114-21.377 26.63" fill="none" stroke="#000"/><polygon points="499.25 -127.05 490.36 -121.28 493.71 -131.33" stroke="#000"/><text x="531" y="-144.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">head</text></g><g id="ah" class="node"><title>g2scanl</title><ellipse cx="591" cy="-105" rx="67.688" ry="18" fill="none" stroke="#000"/><text x="591" y="-101.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">scanl op init list</text></g><g id="ai" class="edge"><title>g2fibs2-&gt;g2scanl</title><path d="m546.92-173.75c-0.8767 10.092-0.562 22.605 4.0774 32.753 1.9313 4.2246 4.6212 8.1661 7.7022 11.775" fill="none" stroke="#000"/><polygon points="561.41 -131.46 565.93 -121.87 556.42 -126.55" stroke="#000"/><text x="560" y="-144.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">tail</text></g><g id="aj" class="edge"><title>g2scanl-&gt;g2fibs2</title><path d="m583.6-123.09c-4.1167-9.8196-9.4396-22.122-14.602-32.907-1.4341-2.996-2.982-6.1053-4.5537-9.1854" fill="none" stroke="#000"/><polygon points="561.27 -163.71 559.75 -174.2 567.48 -166.95" stroke="#000"/><text x="584.5" y="-144.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">list</text></g><g id="ak" class="node"><title>g2+</title><ellipse cx="555" cy="-18" rx="27" ry="18" fill="none" stroke="#000"/><text x="555" y="-14.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">+</text></g><g id="al" class="edge"><title>g2scanl-&gt;g2+</title><path d="m583.54-86.974c-5.0381 12.175-11.777 28.461-17.442 42.151" fill="none" stroke="#000"/><polygon points="569.26 -43.312 562.2 -35.41 562.79 -45.988" stroke="#000"/><text x="583" y="-57.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">op</text></g><g id="am" class="node"><title>g2_3</title><ellipse cx="627" cy="-18" rx="27" ry="18" fill="none" stroke="#000"/><text x="627" y="-14.3" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">3</text></g><g id="an" class="edge"><title>g2scanl-&gt;g2_3</title><path d="m598.46-86.974c5.0381 12.175 11.777 28.461 17.442 42.151" fill="none" stroke="#000"/><polygon points="619.21 -45.988 619.8 -35.41 612.74 -43.312" stroke="#000"/><text x="621.5" y="-57.8" fill="#000000" font-family="Times,serif" font-size="14" text-anchor="middle">init</text></g></g></svg>