Erlang (programming language)/Tutorials/Folding: Difference between revisions
imported>Chris Day No edit summary |
imported>Eric Evers No edit summary |
||
Line 1: | Line 1: | ||
{{subpages}} | {{subpages}} | ||
Fun with folding | Fun with folding | ||
==Fold== | |||
Fold is a powerful tool, when you get to know it. lists:foldr(F,S,L) takes three arguments: | Fold is a powerful tool, when you get to know it. lists:foldr(F,S,L) takes three arguments: | ||
Line 35: | Line 37: | ||
math:exp(1) - 1. | math:exp(1) - 1. | ||
1.718281828459045 | 1.718281828459045 | ||
==Unfold== | |||
The opposite of fold it the unfold. | |||
Unfold takes a seed and builds a list or larger structure, perhaps an infinite stream. | |||
%============================================================ | |||
-module(fun_utils). | |||
-compile(export_all). | |||
% erlang unfold code thanks to Debasish Ghosh | |||
unfold(Seed, Predicate, Transformer) when is_integer(Seed) -> | |||
unfold(Seed, Predicate, Transformer, 1). | |||
unfold(Seed, Predicate, Transformer, Incrementor) -> | |||
unfold(Seed, Predicate, Transformer, Incrementor, []). | |||
unfold(Seed, Predicate, Transformer, Incrementor, Acc) -> | |||
case Predicate(Seed) of | |||
true -> unfold(Incrementor(Seed), | |||
Predicate, | |||
Transformer, | |||
Incrementor, | |||
[Transformer(Seed)|Acc]); | |||
false -> lists:reverse(Acc) | |||
end. | |||
% This front-end makes zip behave like the native lists:zip(L1,L2) | |||
% in the popular erlang lib. | |||
zip(L1,L2) -> | |||
lists:map(fun(L)->list_to_tuple(L) end, zip([L1,L2])). | |||
% a pure 100% list of lists based zip | |||
zip(Ls) -> | |||
unfold(Ls, | |||
fun(X) -> length(hd(X)) > 0 end, | |||
fun(Lists) -> [hd(List) || List <- Lists] end, | |||
fun(Lists) -> [List -- [hd(List)] || List <- Lists] end). | |||
%=================================================================== | |||
% Run it | |||
% 24> c(fun_utils). | |||
% ok | |||
% 25> fun_utils:zip([1,2,3],[4,5,6]). | |||
% [{1,4},{2,5},{3,6}] |
Revision as of 19:02, 2 August 2009
The metadata subpage is missing. You can start it via filling in this form or by following the instructions that come up after clicking on the [show] link to the right. | |||
---|---|---|---|
|
Fun with folding
Fold
Fold is a powerful tool, when you get to know it. lists:foldr(F,S,L) takes three arguments: F is some folding function, S is some starting value, and L is some List that needs folding. Let us do some simple folding. The following fold calculates the lenght of a list. Here the current list item, _C is ignored, and the accumulator, A, counts the number of elements in the list.
1> lists:foldr( fun(_C,A)->A+1 end, 0, [1,2,3]). 3
We could reverse a list with fold if we like.
2> lists:foldr(fun(C,A)->A++[C] end, [], [a,b,c]). [c,b,a]
Or to get fancy we could try a finite difference.
3> lists:foldr( fun(C,{P,A})->{C,[P-C]++A} end, {0,[]}, [1,4,9,16]).
{1,[3,5,7,-16]}
In example 3, we used a tuple to remember the previous value so we could use it for next difference. Fold is a function with a limited attention span. We might like to delete the last item because is has a non-intuitive relation to the source list.
Calculating a continuted calculation with fold seems natural
lists:foldr(fun(C,A)->(A+1)/C end, 1, lists:seq(1,1000)). 1.718281828459045
The answer appears to be the value e-1, which we can verify with:
math:exp(1) - 1. 1.718281828459045
Unfold
The opposite of fold it the unfold. Unfold takes a seed and builds a list or larger structure, perhaps an infinite stream.
%============================================================ -module(fun_utils). -compile(export_all). % erlang unfold code thanks to Debasish Ghosh unfold(Seed, Predicate, Transformer) when is_integer(Seed) -> unfold(Seed, Predicate, Transformer, 1). unfold(Seed, Predicate, Transformer, Incrementor) -> unfold(Seed, Predicate, Transformer, Incrementor, []). unfold(Seed, Predicate, Transformer, Incrementor, Acc) -> case Predicate(Seed) of true -> unfold(Incrementor(Seed), Predicate, Transformer, Incrementor, [Transformer(Seed)|Acc]); false -> lists:reverse(Acc) end. % This front-end makes zip behave like the native lists:zip(L1,L2) % in the popular erlang lib. zip(L1,L2) -> lists:map(fun(L)->list_to_tuple(L) end, zip([L1,L2])). % a pure 100% list of lists based zip zip(Ls) -> unfold(Ls, fun(X) -> length(hd(X)) > 0 end, fun(Lists) -> [hd(List) || List <- Lists] end, fun(Lists) -> [List -- [hd(List)] || List <- Lists] end). %===================================================================
% Run it % 24> c(fun_utils). % ok % 25> fun_utils:zip([1,2,3],[4,5,6]). % [{1,4},{2,5},{3,6}]