ERLANG,使用 zipWith 的无限斐波那契列表

ERLANG, infinite Fibonacci list using zipWith

我有一个包含无限列表的任务。

我必须为无限列表编写 zipWith/3 - 完成

我必须使用这个 zipWith/3 来创建无限的斐波那契数列表 fib/0 - 问题

我必须编写 fibs(N) 从 fib() 获取前 N 个元素 - 完成

这是我目前拥有的:

-module(zipWith).
-export([take/2, zipWith/3, fib/0]).

take(0, _)         -> [];
take(N, [H|LazyT]) -> [H | take(N-1, LazyT())].

zipWith(F, [H1|L1], [H2|L2]) -> [F(H1, H2) | fun() -> zipWith(F, L1(),   L2()) end].

fib() -> ...
fib(L) -> zipWith(fun(X,Y) -> X + Y end, L(), tl(L())).

fibs(N) -> take(N, fib()).

我知道 fib/1 应该是这样的(我很确定 - 如果我弄错了请纠正我)。获取列表本身和没有头部的列表。所以在 [0,1,...] 的情况下 zipWith(add,[0,1,...],[1,...]) 导致添加最后两个数字。但是无论我尝试作为这个 fib()->... 的开始都会导致错误。 我想以某种方式表达它: fib() -> fib([[0,1] ++ fun() -> ... 结束]...)

我想以某种方式开始 fib/1 [0,1,fun()...] 但不知道如何让列表开始。

提前感谢您的建议

我不明白你打算如何在这里使用 zipwith。但是,我想出了以下解决方案:

map(_, []) -> [];
map(F, [H | T]) -> [F(H) | fun() -> map(F, T()) end].

fib1(X, Y) -> [{X, Y} | fun() -> fib1(Y, X+Y) end].

fib() -> map(fun({_X, Y}) -> Y end, fib1(1,1)).

我们的想法是构建一些元素,然后传递下一个数字的上下文。

实际上我不认为这种方法实现了真正的惰性,因为每次浏览列表时都必须重新评估所有值。

更新

如果你想通过 zipWith 实现这一点,你可以绕过这个事实,即序列的每个下一个元素都是前一个元素和当前元素的总和。

所以你可以获取一个元素列表,一个元素列表移动一个,并将每个下一个元素形成为这些列表中元素的总和。

bootstrap 您需要一些第一个元素。您只需应用前两个元素的知识

如你所见,计算第3个元素时你必须先知道2,计算第4个元素时,你必须知道第2和第3个,但你已经计算了第3个。

%% this eveluates the lazy list and just returns normal one
e(L) when is_list(L) -> L; 
e(LazyL) when is_function(LazyL, 0) -> LazyL().

take(0, _)         -> [];
take(N, [H|LazyT]) -> [H | take(N-1, e(LazyT))].

drop(0, T)         -> e(T);
drop(N, [_|LazyT]) -> drop(N-1, e(LazyT)).

zipWith(F, [H1|L1], [H2|L2]) -> [F(H1, H2) | fun() -> zipWith(F, e(L1),   e(L2)) end].

fib() -> [1, 1 | fun() -> zipWith(fun(X,Y) -> X + Y end, fib(), drop(1, fib())) end ].

fibs(N) -> take(N, fib()).

最后的笔记

  1. 现实生活中千万不要这样写。
  2. 这类更有趣的任务是实现埃拉托色尼筛法。后一个任务不是那么做作,这种懒惰的想法真的很优雅