無限リストによるエラトステネスのふるい でも書いたが Stream を使うと Elixir でも遅延評価な無限リストを扱うことができる。その Stream にあるコンストラクタ関数の一つであるところの unfold/2
を使うと、再帰的に処理を行いながらアキュムレータに結果を積んでいく・・・というよくあるパターンを、無限リストとして実装できる。
カッとなって無限に FizzBuzz するストリームを書いてみた。
fizzbuzz = fn
{true, true} -> "FizzBuzz"
{true, false} -> "Fizz"
{false, true} -> "Buzz"
{false, false} -> nil
end
fst = Stream.unfold(1, fn(n) ->
res = case fizzbuzz.({rem(n, 3) == 0, rem(n, 5) == 0}) do
nil -> n
s -> s
end
{res, n + 1}
end)
fst |> Enum.take(100) |> IO.inspect
一見ただの FizzBuzz だが
fst |> Enum.take(100) |> IO.inspect
ここでストリームは Enum.take/1
に評価されるまで遅延評価されている。take(100)
なら 100件を、take(10000)
なら 10,000 件をそのとき初めて処理する。何の役にたつかというと、何の役にも立たない。