-module(gleam@iterator). -compile(no_auto_import). -export([unfold/2, repeatedly/1, repeat/1, from_list/1, fold/3, run/1, to_list/1, step/1, take/2, drop/2, map/2, append/2, flatten/1, flat_map/2, filter/2, cycle/1, range/2, find/2]). -export_type([action/1, iterator/1, step/2]). -type action(ATI) :: stop | {continue, ATI, fun(() -> action(ATI))}. -opaque iterator(ATJ) :: {iterator, fun(() -> action(ATJ))}. -type step(ATK, ATL) :: {next, ATK, ATL} | done. -spec do_unfold(ATO, fun((ATO) -> step(ATP, ATO))) -> fun(() -> action(ATP)). do_unfold(Initial, F) -> fun() -> case F(Initial) of {next, X, Acc} -> {continue, X, do_unfold(Acc, F)}; done -> stop end end. -spec unfold(ATT, fun((ATT) -> step(ATU, ATT))) -> iterator(ATU). unfold(Initial, F) -> {iterator, do_unfold(Initial, F)}. -spec repeatedly(fun(() -> ATY)) -> iterator(ATY). repeatedly(F) -> unfold(nil, fun(_) -> {next, F(), nil} end). -spec repeat(AUA) -> iterator(AUA). repeat(X) -> repeatedly(fun() -> X end). -spec from_list(list(AUC)) -> iterator(AUC). from_list(List) -> Yield = fun(Acc) -> case Acc of [] -> done; [Head | Tail] -> {next, Head, Tail} end end, unfold(List, Yield). -spec do_fold(fun(() -> action(AUF)), AUH, fun((AUF, AUH) -> AUH)) -> AUH. do_fold(Continuation, Initial, F) -> case Continuation() of {continue, Element, Iterator} -> do_fold(Iterator, F(Element, Initial), F); stop -> Initial end. -spec fold(iterator(AUI), AUK, fun((AUI, AUK) -> AUK)) -> AUK. fold(Iterator, Initial, F) -> do_fold(erlang:element(2, Iterator), Initial, F). -spec run(iterator(any())) -> nil. run(Iterator) -> fold(Iterator, nil, fun(_, _) -> nil end). -spec to_list(iterator(AUN)) -> list(AUN). to_list(Iterator) -> gleam@list:reverse(fold(Iterator, [], fun(E, Acc) -> [E | Acc] end)). -spec step(iterator(AUQ)) -> step(AUQ, iterator(AUQ)). step(Iterator) -> case (erlang:element(2, Iterator))() of stop -> done; {continue, E, A} -> {next, E, {iterator, A}} end. -spec do_take(fun(() -> action(AUV)), integer(), list(AUV)) -> list(AUV). do_take(Continuation, Desired, Acc) -> case Desired > 0 of true -> case Continuation() of {continue, Element, Iterator} -> do_take(Iterator, Desired - 1, [Element | Acc]); stop -> gleam@list:reverse(Acc) end; false -> gleam@list:reverse(Acc) end. -spec take(iterator(AUZ), integer()) -> list(AUZ). take(Iterator, Desired) -> do_take(erlang:element(2, Iterator), Desired, []). -spec do_drop(fun(() -> action(AVC)), integer()) -> fun(() -> action(AVC)). do_drop(Continuation, Desired) -> case Desired > 0 of true -> case Continuation() of {continue, _, Iterator} -> do_drop(Iterator, Desired - 1); stop -> fun() -> stop end end; false -> Continuation end. -spec drop(iterator(AVF), integer()) -> iterator(AVF). drop(Iterator, Desired) -> {iterator, do_drop(erlang:element(2, Iterator), Desired)}. -spec do_map(fun(() -> action(AVI)), fun((AVI) -> AVK)) -> fun(() -> action(AVK)). do_map(Continuation, F) -> fun() -> case Continuation() of {continue, E, Continuation@1} -> {continue, F(E), do_map(Continuation@1, F)}; stop -> stop end end. -spec map(iterator(AVM), fun((AVM) -> AVO)) -> iterator(AVO). map(Iterator, F) -> {iterator, do_map(erlang:element(2, Iterator), F)}. -spec do_append(fun(() -> action(AVQ)), fun(() -> action(AVQ))) -> fun(() -> action(AVQ)). do_append(First, Second) -> fun() -> case First() of {continue, E, First@1} -> {continue, E, do_append(First@1, Second)}; stop -> Second() end end. -spec append(iterator(AVU), iterator(AVU)) -> iterator(AVU). append(First, Second) -> {iterator, do_append(erlang:element(2, First), erlang:element(2, Second))}. -spec do_flatten(fun(() -> action(iterator(AVY)))) -> fun(() -> action(AVY)). do_flatten(Continuation) -> fun() -> case Continuation() of {continue, E, Continuation@1} -> (do_append(erlang:element(2, E), do_flatten(Continuation@1)))(); stop -> stop end end. -spec flatten(iterator(iterator(AWC))) -> iterator(AWC). flatten(Iterator) -> {iterator, do_flatten(erlang:element(2, Iterator))}. -spec flat_map(iterator(AWG), fun((AWG) -> iterator(AWI))) -> iterator(AWI). flat_map(Iterator, F) -> flatten(map(Iterator, F)). -spec do_filter(fun(() -> action(AWL)), fun((AWL) -> boolean())) -> fun(() -> action(AWL)). do_filter(Continuation, Predicate) -> fun() -> case Continuation() of {continue, E, Iterator} -> case Predicate(E) of true -> {continue, E, do_filter(Iterator, Predicate)}; false -> (do_filter(Iterator, Predicate))() end; stop -> stop end end. -spec filter(iterator(AWO), fun((AWO) -> boolean())) -> iterator(AWO). filter(Iterator, Predicate) -> {iterator, do_filter(erlang:element(2, Iterator), Predicate)}. -spec do_cycle(fun(() -> action(AWR)), fun(() -> action(AWR))) -> fun(() -> action(AWR)). do_cycle(Next, Reset) -> fun() -> case Next() of {continue, E, Iterator} -> {continue, E, do_cycle(Iterator, Reset)}; stop -> (do_cycle(Reset, Reset))() end end. -spec cycle(iterator(AWV)) -> iterator(AWV). cycle(Iterator) -> {iterator, do_cycle(erlang:element(2, Iterator), erlang:element(2, Iterator))}. -spec do_range(integer(), integer(), integer()) -> fun(() -> action(integer())). do_range(Current, Limit, Inc) -> case Current =:= Limit of true -> fun() -> stop end; false -> fun() -> {continue, Current, do_range(Current + Inc, Limit, Inc)} end end. -spec range(integer(), integer()) -> iterator(integer()). range(Start, Stop) -> {iterator, do_range(Start, Stop, case Start < Stop of true -> 1; false -> -1 end)}. -spec find(iterator(AXD), fun((AXD) -> boolean())) -> {ok, AXD} | {error, nil}. find(Haystack, Is_desired) -> case (erlang:element(2, Haystack))() of {continue, Element, Continuation} -> case Is_desired(Element) of true -> {ok, Element}; false -> find({iterator, Continuation}, Is_desired) end; stop -> {error, nil} end.