Current section
Files
Jump to
Current section
Files
src/zlist.erl
-module(zlist).
-export([
map/2,
filter/2,
filtermap/2,
flatmap/2,
over/3,
dropwhen/2,
dropwhile/2,
append/2,
ciclyc/1,
empty/0,
seq/2,
seq/3,
recurrent/2,
foreach/2,
fold/3,
take/2,
takewhile/2,
take_by/2,
from_list/1,
to_list/1
]).
-type zlist(A) :: fun(() -> maybe_improper_list(A, zlist(A))) | empty_zlist().
-type empty_zlist() :: fun(() -> []).
-export_type([
zlist/1,
empty_zlist/0
]).
%% =============================================================================
%% API functions
%% =============================================================================
-spec empty() -> empty_zlist().
empty() -> fun() -> [] end.
-spec seq(From, To) -> zlist(integer()) when
From :: integer(),
To :: integer().
seq(First, Last) when is_integer(First), is_integer(Last), First-1 =< Last ->
seq_(First, Last).
seq_(Curr, Last) ->
fun() ->
case Curr > Last of
true -> [];
false -> [Curr] ++ seq_(Curr+1, Last)
end
end.
-spec seq(From, To, Incr) -> zlist(integer()) when
From :: integer(),
To :: integer(),
Incr :: integer().
seq(First, Last, Inc) when is_integer(First), is_integer(Last), is_integer(Inc) ->
if
Inc > 0, First - Inc =< Last;
Inc < 0, First - Inc >= Last ->
N = (Last - First + Inc) div Inc,
seq_(N, First, Inc);
Inc =:= 0, First =:= Last ->
seq_(1, First, Inc)
end.
seq_(N, X, D) ->
fun() ->
case N of
0 -> [];
_ -> [X] ++ seq_(N-1, X+D, D)
end
end.
-spec map(fun((A) -> B), zlist(A)) -> zlist(B).
map(Fun, Zlist) ->
fun() ->
case Zlist() of
[Data|Next] ->
[Fun(Data)] ++ map(Fun, Next);
Done -> Done
end
end.
-spec foreach(fun((A) -> ok), zlist(A)) -> ok.
foreach(Fun, Zlist) ->
case Zlist() of
[Data|Next] ->
_ = Fun(Data),
foreach(Fun, Next);
_Done -> ok
end.
-spec filter(fun((A) -> boolean()), zlist(A)) -> zlist(A).
filter(Fun, Zlist) ->
fun() ->
case Zlist() of
[Data|Next] ->
case Fun(Data) of
true -> [Data] ++ filter(Fun, Next);
false -> (filter(Fun, Next))()
end;
Done -> Done
end
end.
-spec filtermap(fun((A) -> {true, B} | false), zlist(A)) -> zlist(B).
filtermap(Fun, Zlist) ->
fun() ->
case Zlist() of
[Data|Next] ->
case Fun(Data) of
{true, Data2} -> [Data2] ++ filtermap(Fun, Next);
false -> (filtermap(Fun, Next))()
end;
Done -> Done
end
end.
-spec fold(fun((A, S) -> S), S, zlist(A)) -> S.
fold(Fun, State, Zlist) ->
case Zlist() of
[Data|Next] ->
fold(Fun, Fun(Data, State), Next);
_Done -> State
end.
-spec flatmap(fun((A) -> zlist(B)), zlist(A)) -> zlist(B).
flatmap(Fun, Zlist) ->
fun() ->
case Zlist() of
[Data|Next] ->
(append(Fun(Data), flatmap(Fun, Next)))();
Done -> Done
end
end.
-spec over(fun((A,S) -> {B, S}), S, zlist(A)) -> zlist(B).
over(Fun, S, Zlist) ->
fun() ->
case Zlist() of
[Data|Next] ->
{Value, S2} = Fun(Data, S),
[Value] ++ over(Fun, S2, Next);
Done -> Done
end
end.
-spec dropwhen(fun((A) -> boolean()), zlist(A)) -> zlist(A).
dropwhen(Fun, Zlist) ->
fun() ->
case Zlist() of
[Data|Next] ->
case Fun(Data) of
true -> [];
false -> [Data] ++ dropwhen(Fun, Next)
end;
Done -> Done
end
end.
-spec dropwhile(fun((A) -> boolean()), zlist(A)) -> zlist(A).
dropwhile(Fun, Zlist) ->
fun() ->
case Zlist() of
[Data|Next]=R ->
case Fun(Data) of
true -> (dropwhile(Fun, Next))();
false -> R
end;
Done -> Done
end
end.
-spec append(zlist(A), zlist(B)) -> zlist(A|B).
append(Zlist1, Zlist2) ->
fun() ->
case Zlist1() of
[Data|Next] -> [Data] ++ append(Next, Zlist2);
_Done -> Zlist2()
end
end.
-spec ciclyc(zlist(A)) -> zlist(A).
ciclyc(Zlist) ->
(fun Loop(Z) ->
fun() ->
case Z() of
[Data|Next] -> [Data] ++ Loop(Next);
_Done -> (ciclyc(Zlist))()
end
end
end)(Zlist).
-spec from_list([A]) -> zlist(A).
from_list(List) ->
fun() ->
case List of
[H|T] -> [H] ++ from_list(T);
_ -> List
end
end.
-spec to_list(zlist(A)) -> [A].
to_list(Zlist) -> lists:reverse(fold(fun(H, T) -> [H|T] end, [], Zlist)).
-spec recurrent(fun((A) -> A), A) -> zlist(A).
recurrent(Fun, S) ->
fun() ->
Next = Fun(S),
[Next] ++ recurrent(Fun, Next)
end.
-spec take(N :: pos_integer(), zlist(A)) -> {[A], zlist(A)}.
take(N, Zlist) when N > 0 ->
take_(N, [], Zlist).
take_(0, Acc, Z) -> {lists:reverse(Acc), Z};
take_(C, Acc, Z) ->
case Z() of
[Data|Next] -> take_(C-1, [Data|Acc], Next);
_Done -> {lists:reverse(Acc), empty()}
end.
-spec takewhile(fun((A) -> boolean()), zlist(A)) -> {[A], zlist(A)}.
takewhile(Fun, Zlist) -> takewhile_(Fun, [], Zlist).
takewhile_(Fun, Acc, Z) ->
case Z() of
[Data|Next] = R ->
case Fun(Data) of
true -> takewhile_(Fun, [Data|Acc], Next);
false -> {lists:reverse(Acc), fun() -> R end}
end;
_Done -> {lists:reverse(Acc), empty()}
end.
-spec take_by(N :: pos_integer(), zlist(A)) -> zlist([A]).
take_by(N, Zlist) when N > 0 ->
fun() ->
case take(N, Zlist) of
{[], EmptyZ} -> EmptyZ();
{List, RestZ} -> [List] ++ take_by(N, RestZ)
end
end.