-module(gens@stream). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -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, flatten/1, filter/2]). -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(HSO) :: {stream, fun(() -> HSO), fun(() -> stream(HSO))}. -file("src/gens/stream.gleam", 12). ?DOC(" `Tail recursive` function for **take**\n"). -spec take_acc(stream(HSP), integer(), list(HSP)) -> list(HSP). 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(HST), integer()) -> list(HST). 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(HSW), fun((HSW) -> HSY)) -> stream(HSY). 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(HTA), fun((HTA) -> boolean())) -> HTA. 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(HTI), integer()) -> stream(HTI). 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(HTL), stream(HTN)) -> stream({HTL, HTN}). 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(HTQ), stream(HTS)) -> list({HTQ, HTS}). 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(HTV), fun((HTV) -> boolean())) -> list(HTV). 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(HTY), HUA, fun((HTY, HUA) -> HUA)) -> stream(HUA). 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(HUC), stream(HUC), fun((HUC, HUC) -> gleam@order:order())) -> stream(HUC). 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(HUG), fun((HUG, fun(() -> HUI)) -> HUI)) -> HUI. 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(HUJ))) -> HUJ. 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(HUU)) -> stream(HUU). from_lazy_list(Lz) -> {stream, fun() -> case gens@lazy:take(Lz, 1) of [] -> erlang:error(#{gleam_error => panic, message => <<"`panic` expression evaluated."/utf8>>, file => <>, 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", 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(HUQ))) -> stream(HUQ). 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(HUM))) -> stream(HUM). 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(HTF), fun((HTF) -> boolean())) -> stream(HTF). 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(HTC), fun((HTC) -> boolean())) -> stream(HTC). 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.