Current section

Files

Jump to
gens src gens.erl
Raw

src/gens.erl

-module(gens).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-define(FILEPATH, "src/gens.gleam").
-export([get/1, gen/2, combine/2, from_list/1, list_repeat/1, merge/3, new/0, take/2, map/2, filter/2, drop/2, from_lazy_list/1, zip/2, list_zip/2]).
-export_type([generator/2, lazy_list/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.
-type generator(DTS, DTT) :: {generator,
DTT,
fun((DTT) -> gleam@option:option({DTS, DTT}))}.
-opaque lazy_list(DTU) :: {lazy_list,
integer(),
fun((integer()) -> DTU),
fun((integer()) -> boolean())}.
-file("src/gens.gleam", 19).
?DOC(
" Returns the next element of a generator and the updated gen\n"
" ```gleam\n"
" let counter =\n"
" Generator(state: 0, next: fn(c) { Some(#(c, c + 1)) })\n"
" case get(counter).0 {\n"
" None -> Nil\n"
" Some(x) -> echo x // -> 0\n"
" }\n"
" ```\n"
).
-spec get(generator(DTV, DTW)) -> {gleam@option:option(DTV),
generator(DTV, DTW)}.
get(G) ->
case (erlang:element(3, G))(erlang:element(2, G)) of
none ->
{none, G};
{some, {X, S}} ->
{{some, X}, {generator, S, erlang:element(3, G)}}
end.
-file("src/gens.gleam", 27).
?DOC(" Tail recursive function for gen\n").
-spec gen_acc(generator(DUC, DUD), integer(), list(DUC)) -> {list(DUC),
generator(DUC, DUD)}.
gen_acc(G, N, Ls) ->
case N > 0 of
false ->
{lists:reverse(Ls), G};
true ->
case get(G) of
{none, _} ->
{lists:reverse(Ls), G};
{{some, X}, G2} ->
gen_acc(G2, N - 1, [X | Ls])
end
end.
-file("src/gens.gleam", 49).
?DOC(
" Generates at most n elements and returns the updated gen\n"
" ```gleam\n"
" let counter =\n"
" Generator(state: 0, next: fn(c) { Some(#(c, c + 1)) })\n"
" let #(nums, _) = gen(counter, 5)\n"
" echo nums // -> [0, 1, 2, 3, 4]\n"
" ```\n"
).
-spec gen(generator(DUK, DUL), integer()) -> {list(DUK), generator(DUK, DUL)}.
gen(G, N) ->
gen_acc(G, N, []).
-file("src/gens.gleam", 65).
?DOC(
" Combines two generators into one, advancing them separately\n"
" ```gleam\n"
" let two_powers =\n"
" Generator(state: 1, next: fn(p) { Some(#(p, p * 2)) })\n"
" let bellow_three =\n"
" Generator(state: 0, next: fn(n) { Some(#(n < 3, n + 1)) })\n"
"\n"
" let z = combine(two_powers, bellow_three)\n"
" let #(res, _) = gen(z, 5)\n"
" echo res\n"
" // -> [#(1, True), #(2, True), #(4, True), #(8, False), #(16, False)]\n"
" ```\n"
).
-spec combine(generator(DUR, DUS), generator(DUV, DUW)) -> generator({DUR, DUV}, {DUS,
DUW}).
combine(G1, G2) ->
{generator,
{erlang:element(2, G1), erlang:element(2, G2)},
fun(State) ->
{State1, State2} = State,
Res1 = (erlang:element(3, G1))(State1),
Res2 = (erlang:element(3, G2))(State2),
case {Res1, Res2} of
{{some, {X, State3}}, {some, {Y, State4}}} ->
{some, {{X, Y}, {State3, State4}}};
{_, _} ->
none
end
end}.
-file("src/gens.gleam", 103).
?DOC(
" Generates the lists elements\n"
" ```gleam\n"
" let gen_fruit = from_list([\"apple\", \"banana\", \"orange\"])\n"
" let #(fruit1, gen_fruit2) = get(gen_fruit)\n"
" echo fruit1\n"
" // -> Some(\"apple\")\n"
" ```\n"
" ```gleam\n"
" let #(fruit2, gen_fruit3) = get(gen_fruit2)\n"
" echo fruit2\n"
" // -> Some(\"banana\")\n"
" ```\n"
" ```gleam\n"
" let #(fruit3, gen_fruit4) = get(gen_fruit3)\n"
" echo fruit3\n"
" // -> Some(\"orange\")\n"
" ```\n"
" ```gleam\n"
" let #(fruit4, _) = get(gen_fruit4)\n"
" echo fruit4\n"
" // -> None\n"
" ```\n"
).
-spec from_list(list(DVB)) -> generator(DVB, list(DVB)).
from_list(L) ->
{generator, L, fun(Ls) -> case Ls of
[] ->
none;
[X | Rest] ->
{some, {X, Rest}}
end end}.
-file("src/gens.gleam", 119).
?DOC(
" Generates the lists elements on repeat\n"
" ```gleam\n"
" let gen_fruit = list_repeat([\"apple\", \"banana\", \"orange\"])\n"
" let #(fruits, _) = gen(gen_fruit, 5)\n"
" echo fruits\n"
" // -> [\"apple\", \"banana\", \"orange\", \"apple\", \"banana\"]\n"
" ```\n"
).
-spec list_repeat(list(DVG)) -> generator(DVG, {list(DVG), list(DVG)}).
list_repeat(L) ->
{generator,
{L, L},
fun(List_pair) ->
{Current, Original} = List_pair,
case Current of
[] ->
none;
[X | Rest] ->
case Rest of
[] ->
{some, {X, {Original, Original}}};
_ ->
{some, {X, {Rest, Original}}}
end
end
end}.
-file("src/gens.gleam", 160).
?DOC(
" Merges two `sorted` generators into one\n"
" ```gleam\n"
" let counter1 = Generator(0, fn(c) { Some(#(c, c + 1)) })\n"
" let counter2 = Generator(0, fn(c) { Some(#(c, c + 2)) })\n"
" let merged = merge(counter1, counter2, int.compare)\n"
" merged \n"
" |> gen(8) \n"
" |> echo\n"
" // -> #([0, 0, 1, 2, 2, 3, 4, 4], Generator(#(5, 6), fn() { ... }))\n"
" ```\n"
).
-spec merge(
generator(DVR, DVS),
generator(DVR, DVV),
fun((DVR, DVR) -> gleam@order:order())
) -> generator(DVR, {DVS, DVV}).
merge(G1, G2, Comp) ->
{generator,
{erlang:element(2, G1), erlang:element(2, G2)},
fun(S) ->
{State1, State2} = S,
case {(erlang:element(3, G1))(State1),
(erlang:element(3, G2))(State2)} of
{{some, {X1, St1}}, {some, {X2, St2}}} ->
case Comp(X1, X2) of
gt ->
{some, {X2, {State1, St2}}};
_ ->
{some, {X1, {St1, State2}}}
end;
{{some, {X1@1, St1@1}}, none} ->
{some, {X1@1, {St1@1, State2}}};
{none, {some, {X2@1, St2@1}}} ->
{some, {X2@1, {State1, St2@1}}};
{none, none} ->
none
end
end}.
-file("src/gens.gleam", 189).
?DOC(
" Default LazyList for the list of `natural numbers` [0..]\n"
" ```gleam\n"
" new() |> take(5)\n"
" // -> [0, 1, 2, 3, 4]\n"
" ```\n"
).
-spec new() -> lazy_list(integer()).
new() ->
{lazy_list, 0, fun(X) -> X end, fun(_) -> true end}.
-file("src/gens.gleam", 194).
?DOC(" `Tail recursive` function for **take**\n").
-spec take_acc(
integer(),
integer(),
integer(),
fun((integer()) -> DWB),
fun((integer()) -> boolean()),
list(DWB)
) -> list(DWB).
take_acc(Index, Step, Total, Fmap, Filt, Acc) ->
case Step < Total of
false ->
_pipe = Acc,
lists:reverse(_pipe);
true ->
case Filt(Index) of
false ->
take_acc(Index + 1, Step, Total, Fmap, Filt, Acc);
true ->
case Step >= 0 of
false ->
take_acc(
Index + 1,
Step + 1,
Total,
Fmap,
Filt,
Acc
);
true ->
take_acc(
Index + 1,
Step + 1,
Total,
Fmap,
Filt,
[Fmap(Index) | Acc]
)
end
end
end.
-file("src/gens.gleam", 225).
?DOC(
" **Takes** a `finite` number of elements from a LazyList\n"
" ```gleam\n"
" take(new(), 5)\n"
" // -> [0, 1, 2, 3, 4]\n"
" ```\n"
).
-spec take(lazy_list(DWE), integer()) -> list(DWE).
take(Ga, N) ->
case Ga of
{lazy_list, Index, Amap, Afilt} ->
take_acc(Index, 0, N, Amap, Afilt, [])
end.
-file("src/gens.gleam", 239).
?DOC(
" **Maps** each element of the takeerated list\n"
" ```gleam\n"
" new()\n"
" |> map(fn(x) { x + 3 })\n"
" |> map(int.to_string)\n"
" |> take(5)\n"
" // -> [\"3\", \"4\", \"5\", \"6\", \"7\"]\n"
" ```\n"
).
-spec map(lazy_list(DWH), fun((DWH) -> DWJ)) -> lazy_list(DWJ).
map(Ga, F) ->
case Ga of
{lazy_list, Index, Amap, Afilt} ->
{lazy_list, Index, fun(N) -> F(Amap(N)) end, Afilt}
end.
-file("src/gens.gleam", 253).
?DOC(
" **Filters** elements from the takeerated list\n"
" ```gleam\n"
" new()\n"
" |> filter(fn(x) { x % 2 == 0 })\n"
" |> filter(fn(x) { x != 4 })\n"
" |> take(5)\n"
" // -> [0, 2, 6, 8, 10]\n"
" ```\n"
).
-spec filter(lazy_list(DWL), fun((DWL) -> boolean())) -> lazy_list(DWL).
filter(Ga, F) ->
case Ga of
{lazy_list, Index, Amap, Afilt} ->
{lazy_list, Index, Amap, fun(N) -> Afilt(N) andalso F(Amap(N)) end}
end.
-file("src/gens.gleam", 261).
-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", 287).
?DOC(
" **Drops** the first n elements of a LazyList\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"
" |> take(5)\n"
" // -> [4, 6, 8, 10, 12]\n"
" ```\n"
" ```gleam\n"
" new() // [0, 1, 2, 3, 4..]\n"
" |> filter(int.is_even) // [0, 2, 4, 6, 8..]\n"
" |> drop(4) // [8, 10, 12..]\n"
" |> take(5)\n"
" // -> [8, 10, 12, 14, 16]\n"
" ```\n"
).
-spec drop(lazy_list(DWO), integer()) -> lazy_list(DWO).
drop(Ga, Steps) ->
case Steps >= 0 of
false ->
Ga;
true ->
case Ga of
{lazy_list, Index, Amap, Afilt} ->
{lazy_list, advance(Index, Steps, Afilt), Amap, Afilt}
end
end.
-file("src/gens.gleam", 141).
?DOC(
" Generates elements from the lazy list\n"
" ```gleam\n"
" let infinite_list = new() |> drop(3) |> map(fn(x) { x * 10 })\n"
" let ten_gen = from_lazy_list(infinite_list)\n"
" let #(res, _) = gen(ten_gen, 10)\n"
" echo res\n"
" // -> [30, 40, 50, 60, 70, 80, 90, 100, 110, 120]\n"
" ```\n"
).
-spec from_lazy_list(lazy_list(DVM)) -> generator(DVM, lazy_list(DVM)).
from_lazy_list(L) ->
{generator, L, fun(Ls) -> case take(Ls, 1) of
[] ->
none;
[X | _] ->
{some,
{X,
begin
_pipe = Ls,
drop(_pipe, 1)
end}}
end end}.
-file("src/gens.gleam", 309).
?DOC(
" **Zips** two LazyLists into one\n"
" - The resulting index is the maximum of the two takes \n"
" - The filters get combined\n"
" - For separate indexes, do `list.zip(take(g1, n), take(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"
" |> take(3)\n"
" // -> [#(2, 0), #(4, 2), #(6, 4)]\n"
" ```\n"
).
-spec zip(lazy_list(DWR), lazy_list(DWT)) -> lazy_list({DWR, DWT}).
zip(Ga, Gb) ->
{lazy_list, Aindex, Amap, Afilt} = Ga,
{lazy_list, Bindex, Bmap, Bfilt} = Gb,
{lazy_list,
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", 323).
?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(DWW), lazy_list(DWY)) -> list({DWW, DWY}).
list_zip(La, Gb) ->
gleam@list:zip(La, take(Gb, erlang:length(La))).