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()).
最后的笔记
- 现实生活中千万不要这样写。
- 这类更有趣的任务是实现埃拉托色尼筛法。后一个任务不是那么做作,这种懒惰的想法真的很优雅
我有一个包含无限列表的任务。
我必须为无限列表编写 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()).
最后的笔记
- 现实生活中千万不要这样写。
- 这类更有趣的任务是实现埃拉托色尼筛法。后一个任务不是那么做作,这种懒惰的想法真的很优雅