Current section
Files
Jump to
Current section
Files
src/gens.erl
-module(gens).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-define(FILEPATH, "src/gens.gleam").
-export([new/0, gen/2, map/2, filter/2, drop/2, next/1, zip/2, list_zip/2]).
-export_type([generator/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-opaque generator(DTS) :: {generator,
integer(),
fun((integer()) -> DTS),
fun((integer()) -> boolean())}.
-file("src/gens.gleam", 13).
?DOC(
" Default generator for the list of `natural numbers` [0..]\n"
" ```gleam\n"
" new() |> gen(5)\n"
" // -> [0, 1, 2, 3, 4]\n"
" ```\n"
).
-spec new() -> generator(integer()).
new() ->
{generator, 0, fun(X) -> X end, fun(_) -> true end}.
-file("src/gens.gleam", 18).
?DOC(" `Tail recursive` function for **gen**\n").
-spec gen_acc(
integer(),
integer(),
integer(),
fun((integer()) -> DTU),
fun((integer()) -> boolean()),
list(DTU)
) -> list(DTU).
gen_acc(Index, Step, Total, Fmap, Filt, Acc) ->
case Step < Total of
false ->
_pipe = Acc,
lists:reverse(_pipe);
true ->
case Filt(Index) of
false ->
gen_acc(Index + 1, Step, Total, Fmap, Filt, Acc);
true ->
case Step >= 0 of
false ->
gen_acc(Index + 1, Step + 1, Total, Fmap, Filt, Acc);
true ->
gen_acc(
Index + 1,
Step + 1,
Total,
Fmap,
Filt,
[Fmap(Index) | Acc]
)
end
end
end.
-file("src/gens.gleam", 49).
?DOC(
" **Generates** a `finite list` from a generator and a length\n"
" ```gleam\n"
" gen(new(), 5)\n"
" // -> [0, 1, 2, 3, 4]\n"
" ```\n"
).
-spec gen(generator(DTX), integer()) -> list(DTX).
gen(Ga, N) ->
case Ga of
{generator, Index, Amap, Afilt} ->
gen_acc(Index, 0, N, Amap, Afilt, [])
end.
-file("src/gens.gleam", 63).
?DOC(
" **Maps** each element of the generated list\n"
" ```gleam\n"
" new()\n"
" |> map(fn(x) { x + 3 })\n"
" |> map(int.to_string)\n"
" |> gen(5)\n"
" // -> [\"3\", \"4\", \"5\", \"6\", \"7\"]\n"
" ```\n"
).
-spec map(generator(DUA), fun((DUA) -> DUC)) -> generator(DUC).
map(Ga, F) ->
case Ga of
{generator, Index, Amap, Afilt} ->
{generator, Index, fun(N) -> F(Amap(N)) end, Afilt}
end.
-file("src/gens.gleam", 78).
?DOC(
" **Filters** elements from the generated list\n"
" ```gleam\n"
" new()\n"
" |> filter(fn(x) { x % 2 == 0 })\n"
" |> filter(fn(x) { x != 4 })\n"
" |> gen(5)\n"
" // -> [0, 2, 6, 8, 10]\n"
" ```\n"
).
-spec filter(generator(DUE), fun((DUE) -> boolean())) -> generator(DUE).
filter(Ga, F) ->
case Ga of
{generator, Index, Amap, Afilt} ->
{generator, Index, Amap, fun(N) -> Afilt(N) andalso F(Amap(N)) end}
end.
-file("src/gens.gleam", 86).
-spec advance(integer(), integer(), fun((integer()) -> boolean())) -> integer().
advance(Index, Steps, Filt) ->
case Steps >= 0 of
false ->
Index - 1;
true ->
case Filt(Index) of
false ->
advance(Index + 1, Steps, Filt);
true ->
advance(Index + 1, Steps - 1, Filt)
end
end.
-file("src/gens.gleam", 110).
?DOC(
" **Drops** the first n generated elements\n"
" ```gleam\n"
" new() // [0, 1, 2, 3, 4..]\n"
" |> drop(4) // [4, 5, 6, 7..]\n"
" |> filter(int.is_even) // [4, 6, 8..]\n"
" |> gen(5)\n"
" // -> [4, 6, 8, 10, 12]\n"
" new() // [0, 1, 2, 3, 4..]\n"
" |> filter(int.is_even) // [0, 2, 4, 6, 8..]\n"
" |> drop(4) // [8, 10, 12..]\n"
" |> gen(5)\n"
" // -> [8, 10, 12, 14, 16]\n"
" ```\n"
).
-spec drop(generator(DUH), integer()) -> generator(DUH).
drop(Ga, Steps) ->
case Steps >= 0 of
false ->
Ga;
true ->
case Ga of
{generator, Index, Amap, Afilt} ->
{generator, advance(Index, Steps, Afilt), Amap, Afilt}
end
end.
-file("src/gens.gleam", 122).
-spec next_index(
integer(),
fun((integer()) -> DUK),
fun((integer()) -> boolean())
) -> {DUK, integer()}.
next_index(Index, Fmap, Filt) ->
case Filt(Index) of
false ->
next_index(Index + 1, Fmap, Filt);
true ->
{Fmap(Index), Index}
end.
-file("src/gens.gleam", 140).
?DOC(
" **Yields** one element and advances the generator\n"
" ```gleam\n"
" let #(x, g) = new() |> next\n"
" // -> #(0, Generator(Int))\n"
" g |> gen(3)\n"
" // -> [1, 2, 3]\n"
" ```\n"
).
-spec next(generator(DUL)) -> {DUL, generator(DUL)}.
next(Ga) ->
case Ga of
{generator, Index, Amap, Afilt} ->
{Element, New_index} = next_index(Index, Amap, Afilt),
{Element, {generator, New_index + 1, Amap, Afilt}}
end.
-file("src/gens.gleam", 160).
?DOC(
" **Combines** two generators into one \\\n"
" - The resulting index is the maximum of the two gens \n"
" - The filters get combined\n"
" - For separate indexes, do `list.zip(gen(g1, n), gen(g2, n))`\n"
" ```gleam\n"
" let g1 = new() |> map(fn(x) { x + 2 })\n"
" let g2 = new() |> filter(int.is_even)\n"
" zip(g1, g2)\n"
" |> gen(3)\n"
" // -> [#(2, 0), #(4, 2), #(6, 4)]\n"
" ```\n"
).
-spec zip(generator(DUO), generator(DUQ)) -> generator({DUO, DUQ}).
zip(Ga, Gb) ->
{generator, Aindex, Amap, Afilt} = Ga,
{generator, Bindex, Bmap, Bfilt} = Gb,
{generator,
gleam@int:max(Aindex, Bindex),
fun(N) -> {Amap(N), Bmap(N)} end,
fun(N@1) -> Afilt(N@1) andalso Bfilt(N@1) end}.
-file("src/gens.gleam", 174).
?DOC(
" **Zips** a list with an infinite list\n"
" ```gleam\n"
" [\"a\", \"b\", \"c\"] \n"
" |> list_zip(new())\n"
" // -> [#(\"a\", 0), #(\"b\", 1), #(\"c\", 2)]\n"
" ```\n"
).
-spec list_zip(list(DUT), generator(DUV)) -> list({DUT, DUV}).
list_zip(La, Gb) ->
gleam@list:zip(La, gen(Gb, erlang:length(La))).