-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))).