Source

Learn You Some Erlang / stream.erl

Full commit
-module(stream).
-export([make/2, next/1]).
-export_type([generator/1]).

-type generator(T) :: fun(() -> {T, generator(T)}).

-spec make(fun((T) -> T), T) -> generator(T).
make(F, T) ->
    fun() ->
        Val = F(T),
        {Val, make(F, Val)}
    end.

-spec next(generator(T)) -> {T, generator(T)}.
next(Generator) -> Generator().

%%% Uncomment this (and move exports to the top) if
%%% you ever want a more complete stream module, although still
%%% minimal.
%-export([filter/2, sublist/2]).
%-export([main/0]).
%
%-spec filter(fun((T) -> boolean()), generator(T)) -> generator(T).
%filter(Pred, Generator) ->
%    fun() ->
%        {Val, Next} = maybe_retry(Pred, Generator),
%        {Val, filter(Pred, Next)}
%    end.
%
%maybe_retry(Pred, Generator) ->
%    Pair = {Val, Next} = Generator(),
%    case Pred(Val) of
%        true -> Pair;
%        false -> maybe_retry(Pred, Next)
%    end.
%
%-spec sublist(N::pos_integer(), generator(T)) -> {[T,...], generator(T)}.
%sublist(N, Generator) -> sublist(N, Generator, []).
%
%sublist(0, Generator, Acc) ->
%    {lists:reverse(Acc), Generator};
%sublist(N, Generator, Acc) ->
%    {Val, Next} = Generator(),
%    sublist(N-1, Next, [Val|Acc]).
%
%main() ->
%    Incr = make(fun(N) -> N+1 end, 0),
%    {1, N1} = next(Incr),
%    {2, N2} = next(N1),
%    N3 = filter(fun(N) -> N rem 2 =:= 0 end, N2),
%    {[4,6,8], _} = sublist(3, N3).