Current section

Files

Jump to
gens src gens@stream.erl
Raw

src/gens@stream.erl

-module(gens@stream).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gens/stream.gleam").
-export([take/2, map/2, drop/2, zip/2, list_zip/2, while/2, scan/3, merge/3, fold/2, from_lazy_list/1, to_lazy_list/1, flatten/1, filter/2, distinct/1]).
-export_type([stream/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.
?MODULEDOC("================== Stream ==================\n").
-type stream(HQG) :: {stream, fun(() -> HQG), fun(() -> stream(HQG))}.
-file("src/gens/stream.gleam", 12).
?DOC(" `Tail recursive` function for **take**\n").
-spec take_acc(stream(HQH), integer(), list(HQH)) -> list(HQH).
take_acc(Stream, N, Acc) ->
case N > 0 of
false ->
lists:reverse(Acc);
true ->
take_acc(
(erlang:element(3, Stream))(),
N - 1,
[(erlang:element(2, Stream))() | Acc]
)
end.
-file("src/gens/stream.gleam", 30).
?DOC(
" **Takes** a `finite` number of elements from the Stream\n"
" ```gleam\n"
" pub fn ones() -> Stream(Int) {\n"
" Stream(head: fn() { 1 }, tail: ones)\n"
" }\n"
" ```\n"
" ```gleam\n"
" ones()\n"
" |> take(5)\n"
" // -> [1, 1, 1, 1, 1]\n"
" ```\n"
).
-spec take(stream(HQL), integer()) -> list(HQL).
take(Stream, N) ->
take_acc(Stream, N, []).
-file("src/gens/stream.gleam", 55).
?DOC(
" **Maps** each element of the Stream\n"
" ```gleam\n"
" pub fn alt(positive: Bool) -> Stream(Int) {\n"
" Stream(\n"
" head: fn() {\n"
" case positive {\n"
" True -> 1\n"
" False -> -1\n"
" }\n"
" },\n"
" tail: fn() { alt(!positive) },\n"
" )\n"
" }\n"
" ```\n"
" ```gleam\n"
" alt(True)\n"
" |> map(fn(x) { x * 2 })\n"
" |> map(fn(x) { int.to_string(x) <> \" oranges\" })\n"
" |> take(5)\n"
" // -> [\"2 oranges\", \"-2 oranges\", \"2 oranges\", \"-2 oranges\", \"2 oranges\"]\n"
" ```\n"
).
-spec map(stream(HQO), fun((HQO) -> HQQ)) -> stream(HQQ).
map(Stream, F) ->
{stream,
fun() -> F((erlang:element(2, Stream))()) end,
fun() -> map((erlang:element(3, Stream))(), F) end}.
-file("src/gens/stream.gleam", 60).
?DOC(" Lazy function for getting the filtered stream's head\n").
-spec loop_head(stream(HQS), fun((HQS) -> boolean())) -> HQS.
loop_head(Stream, Pred) ->
Current = (erlang:element(2, Stream))(),
case Pred(Current) of
true ->
Current;
false ->
loop_head((erlang:element(3, Stream))(), Pred)
end.
-file("src/gens/stream.gleam", 106).
?DOC(
" **Drops** the first n elements from the Stream\n"
" ```gleam\n"
" pub fn powers() -> Stream(Int) {\n"
" Stream(head: fn() { 1 }, tail: fn() { map(powers(), fn(x) { x * 2 }) })\n"
" }\n"
" ```\n"
" ```gleam\n"
" powers() // 1, 2, 4, 8, 16..\n"
" |> drop(3)\n"
" |> take(5)\n"
" // -> [8, 16, 32, 64, 128]\n"
" ```\n"
).
-spec drop(stream(HRA), integer()) -> stream(HRA).
drop(Stream, N) ->
case N > 0 of
true ->
drop((erlang:element(3, Stream))(), N - 1);
false ->
Stream
end.
-file("src/gens/stream.gleam", 119).
?DOC(
" **Zips** two Streams togheter\n"
" ```gleam\n"
" zip(naturals(), drop(naturals(), 5))\n"
" |> take(3)\n"
" |> [#(0, 5), #(1, 6), #(2, 7)]\n"
" ```\n"
).
-spec zip(stream(HRD), stream(HRF)) -> stream({HRD, HRF}).
zip(A_stream, B_stream) ->
{stream,
fun() ->
{(erlang:element(2, A_stream))(), (erlang:element(2, B_stream))()}
end,
fun() ->
zip(
(erlang:element(3, A_stream))(),
(erlang:element(3, B_stream))()
)
end}.
-file("src/gens/stream.gleam", 130).
?DOC(
" **Zips** a list with a Stream\n"
" ```gleam\n"
" list_zip([\"a\", \"b\", \"c\"], naturals())\n"
" // -> [#(\"a\", 0), #(\"b\", 1), #(\"c\", 2)]\n"
" ```\n"
).
-spec list_zip(list(HRI), stream(HRK)) -> list({HRI, HRK}).
list_zip(List, Stream) ->
case List of
[] ->
[];
[X | Xs] ->
[{X, (erlang:element(2, Stream))()} |
list_zip(Xs, (erlang:element(3, Stream))())]
end.
-file("src/gens/stream.gleam", 143).
?DOC(
" **Takes** elements from the Stream until the condition is false\n"
" ```gleam\n"
" naturals()\n"
" |> while(fn(x) { x < 5 })\n"
" // -> [0, 1, 2, 3, 4]\n"
" ```\n"
).
-spec while(stream(HRN), fun((HRN) -> boolean())) -> list(HRN).
while(Stream, Condition) ->
case Condition((erlang:element(2, Stream))()) of
false ->
[];
true ->
[(erlang:element(2, Stream))() |
while((erlang:element(3, Stream))(), Condition)]
end.
-file("src/gens/stream.gleam", 162).
?DOC(
" **Scans** the Stream and reconstructs it using an accumulator\n"
" ```gleam\n"
" pub fn dummy() -> Stream(Nil) {\n"
" Stream(head: fn() { Nil }, tail: dummy)\n"
" }\n"
" ```\n"
" ```gleam\n"
" let evens: Stream(Int) = scan(dummy(), 0, fn(_, acc) { acc + 2 })\n"
" evens\n"
" |> take(5)\n"
" // -> [0, 2, 4, 6, 8]\n"
" ```\n"
).
-spec scan(stream(HRQ), HRS, fun((HRQ, HRS) -> HRS)) -> stream(HRS).
scan(Stream, Acc, F) ->
{stream,
fun() -> Acc end,
fun() ->
scan(
(erlang:element(3, Stream))(),
F((erlang:element(2, Stream))(), Acc),
F
)
end}.
-file("src/gens/stream.gleam", 174).
?DOC(
" **Merges** two sorted Streams\n"
" ```gleam\n"
" merge(naturals(), naturals() |> map(fn(x) { x * 2 }), int.compare)\n"
" |> take(8)\n"
" // -> [0, 0, 1, 2, 2, 3, 4, 4]\n"
" ```\n"
).
-spec merge(stream(HRU), stream(HRU), fun((HRU, HRU) -> gleam@order:order())) -> stream(HRU).
merge(Stream1, Stream2, Compare) ->
{stream,
fun() ->
case Compare(
(erlang:element(2, Stream1))(),
(erlang:element(2, Stream2))()
) of
gt ->
(erlang:element(2, Stream2))();
_ ->
(erlang:element(2, Stream1))()
end
end,
fun() ->
case Compare(
(erlang:element(2, Stream1))(),
(erlang:element(2, Stream2))()
) of
gt ->
merge(Stream1, (erlang:element(3, Stream2))(), Compare);
_ ->
merge((erlang:element(3, Stream1))(), Stream2, Compare)
end
end}.
-file("src/gens/stream.gleam", 205).
?DOC(
" **Folds** the Stream into a single value using an accumulator\n"
" ```gleam\n"
" let stream_or = fn(s: Stream(Bool)) -> Bool {\n"
" fold(s, fn(x, next) { x || next() })\n"
" }\n"
" // If at least one element is True, then the fold ends\n"
" // If all elements in the Stream are False, the fold runs infinitely\n"
" stream_or(naturals() |> map(fn(x) { x == 10 }))\n"
" // -> True\n"
" ```\n"
).
-spec fold(stream(HRY), fun((HRY, fun(() -> HSA)) -> HSA)) -> HSA.
fold(Stream, F) ->
F(
(erlang:element(2, Stream))(),
fun() -> fold((erlang:element(3, Stream))(), F) end
).
-file("src/gens/stream.gleam", 210).
?DOC(" Lazy function for getting the flattened stream's head\n").
-spec loop_flatten_head(stream(list(HSB))) -> HSB.
loop_flatten_head(Stream) ->
case (erlang:element(2, Stream))() of
[X | _] ->
X;
[] ->
loop_flatten_head((erlang:element(3, Stream))())
end.
-file("src/gens/stream.gleam", 256).
?DOC(
" Conversion from **LazyList** to **Stream**\n"
" ```gleam\n"
" let lazy_odds =\n"
" lazy.new()\n"
" |> lazy.filter(int.is_odd)\n"
" |> lazy.map(int.to_string)\n"
" let stream_odds = from_lazy_list(lazy_odds)\n"
" stream_odds\n"
" |> take(5)\n"
" // -> [\"1\", \"3\", \"5\", \"7\", \"9\"]\n"
" ```\n"
).
-spec from_lazy_list(gens@lazy:lazy_list(HSM)) -> stream(HSM).
from_lazy_list(Lz) ->
{stream, fun() -> case gens@lazy:take(Lz, 1) of
[] ->
erlang:error(#{gleam_error => panic,
message => <<"`panic` expression evaluated."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"gens/stream"/utf8>>,
function => <<"from_lazy_list"/utf8>>,
line => 260});
[X | _] ->
X
end end, fun() -> from_lazy_list(gens@lazy:drop(Lz, 1)) end}.
-file("src/gens/stream.gleam", 279).
?DOC(
" Conversion from **Stream** to **LazyList**\n"
" ```gleam\n"
" let stream_evens =\n"
" naturals()\n"
" |> filter(int.is_even)\n"
" |> map(int.to_string)\n"
" let lazy_evens = to_lazy_list(stream_evens)\n"
" lazy_evens \n"
" |> lazy.take(5)\n"
" // -> [\"0\", \"2\", \"4\", \"6\", \"8\"]\n"
" ```\n"
).
-spec to_lazy_list(stream(HSP)) -> gens@lazy:lazy_list(HSP).
to_lazy_list(S) ->
_pipe = gens@lazy:new(),
gens@lazy:map(_pipe, fun(N) -> (erlang:element(2, drop(S, N)))() end).
-file("src/gens/stream.gleam", 239).
?DOC(
" **Flatten** a Stream of Lists\n"
" ```gleam\n"
" let repeat_stream = naturals() |> map(fn(x) { list.repeat(x, x) })\n"
" repeat_stream\n"
" |> take(5)\n"
" // -> [[], [1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]\n"
" repeat_stream\n"
" |> flatten()\n"
" |> take(10)\n"
" // -> [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]\n"
" ```\n"
).
-spec flatten(stream(list(HSI))) -> stream(HSI).
flatten(Stream) ->
{stream,
fun() -> loop_flatten_head(Stream) end,
fun() -> loop_flatten_tail(Stream) end}.
-file("src/gens/stream.gleam", 218).
?DOC(" Lazy function for getting the flattened stream's tail\n").
-spec loop_flatten_tail(stream(list(HSE))) -> stream(HSE).
loop_flatten_tail(Stream) ->
case (erlang:element(2, Stream))() of
[_ | Xs] ->
New_stream = {stream, fun() -> Xs end, erlang:element(3, Stream)},
flatten(New_stream);
[] ->
loop_flatten_tail((erlang:element(3, Stream))())
end.
-file("src/gens/stream.gleam", 88).
?DOC(
" **Filters** elements from the Stream\n"
" ```gleam\n"
" pub fn naturals() -> Stream(Int) {\n"
" Stream(head: fn() { 0 }, tail: fn() { map(naturals(), fn(x) { x + 1 }) })\n"
" }\n"
" ```\n"
" ```gleam\n"
" filter(naturals(), fn(x) { x % 3 == 0 })\n"
" |> take(5)\n"
" // -> [0, 3, 6, 9, 12]\n"
" ```\n"
).
-spec filter(stream(HQX), fun((HQX) -> boolean())) -> stream(HQX).
filter(Stream, Pred) ->
{stream,
fun() -> loop_head(Stream, Pred) end,
fun() -> loop_tail(Stream, Pred) end}.
-file("src/gens/stream.gleam", 69).
?DOC(" Lazy function for getting the filtered stream's tail\n").
-spec loop_tail(stream(HQU), fun((HQU) -> boolean())) -> stream(HQU).
loop_tail(Stream, Pred) ->
Current = (erlang:element(2, Stream))(),
case Pred(Current) of
true ->
filter((erlang:element(3, Stream))(), Pred);
false ->
loop_tail((erlang:element(3, Stream))(), Pred)
end.
-file("src/gens/stream.gleam", 302).
?DOC(
" Filters out **duplicate** elements of a Stream\n"
" ```gleam\n"
" map(naturals(), fn(x) { x / 3 })\n"
" |> take(10)\n"
" // -> [0, 0, 0, 1, 1, 1, 2, 2, 2, 3]\n"
" map(naturals(), fn(x) { x / 3 })\n"
" |> distinct()\n"
" |> take(5)\n"
" // -> [0, 1, 2, 3, 4]\n"
" ```\n"
" ```gleam\n"
" naturals()\n"
" |> map(fn(x) { [x, x + 3] })\n"
" |> flatten()\n"
" |> distinct()\n"
" |> take(10)\n"
" // -> [0, 3, 1, 4, 2, 5, 6, 7, 8, 9]\n"
" ```\n"
).
-spec distinct(stream(HSS)) -> stream(HSS).
distinct(Stream) ->
{stream,
erlang:element(2, Stream),
fun() ->
filter(
distinct((erlang:element(3, Stream))()),
fun(X) -> X /= (erlang:element(2, Stream))() end
)
end}.