Skip to content

Instantly share code, notes, and snippets.

@ericmoritz
Created July 27, 2012 19:01
Show Gist options
  • Save ericmoritz/3189841 to your computer and use it in GitHub Desktop.
Save ericmoritz/3189841 to your computer and use it in GitHub Desktop.
An experiment with immutable iterators.
%%% File : step.erl
%%% Author : Moritz <emoritz@gci-esansone>
%%% Description : An example of an iterator protocol
%%% Created : 27 Jul 2012 by Eric Moritz <[email protected]>
%%
%% Goals
%%
%% - Pausable iteration
%% - Infinite streams
-module(step).
-export([range/1, to_list/1, count/0, take/2]).
-type iterable() :: {StepValue :: any(), StepState :: any()} | done.
-type iterator() :: {Next :: fun(), iterable()}.
-spec range(integer()) -> iterator().
range(N) ->
{fun range_iter/1, {0, N}}.
% An example of an infinate stream of real numbers starting at 0
count() ->
{fun count/1, {0, '_'}}.
count({N, '_'}) ->
{N+1, '_'}.
-spec range_iter(iterable()) -> iterable().
range_iter({_, 1}) ->
done;
range_iter({I, N}) ->
{I+1, N-1}.
-spec to_list(iterator()) -> list().
to_list(Iterator) ->
to_list(Iterator, []).
to_list({_Next, done}, Accum) ->
lists:reverse(Accum);
to_list({Next, {Val, _} = Iterable}, Accum) ->
to_list({Next, Next(Iterable)}, [Val|Accum]).
take(N, {_Next, {Val, _}} = Iterator) ->
% use to_list with a take iterator (this is getting crazy!)
to_list({fun take_iter/1, {Val, {N, Iterator}}}).
take_iter({_, {1, _}}) ->
done;
take_iter({_LastVal, {I, {Next, Iterable}}}) ->
Iterable2 = Next(Iterable),
{Val, _} = Iterable2,
Iterator2 = {Next, Iterable2},
{Val, {I-1, Iterator2}}.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment