はじめに
流行りに乗ってみました。すでにn番煎じでした。すいません
しかも仕様を間違えて永遠に続けられるようにしてしまいました。
でもStreamモジュールの勉強になりました。
#Streamとは
Elixirにはリスト用のモジュールとして即時評価なEnumモジュールと遅延評価なStreamモジュールがあります。
今回Streamモジュールをつかった遅延評価な感じで実装してみました。
常に5word分バッファしながら動きバッファの内容が条件にマッチングしたら
キ・ヨ・シ!をリストに追加します。
実装結果は以下のとおりです。
defmodule Zundoko do
@zun "ズン "
@doko "ドコ "
@kiyoshi "キ・ヨ・シ!"
def try(n) do
zundoko |> kiyoshi |> Enum.take(n) |> IO.puts
end
def zundoko do
Stream.repeatedly(fn -> Enum.random([@zun, @doko]) end)
end
def kiyoshi(zundoko) do
zundoko |> Stream.transform([], fn e, acc ->
if Enum.count(acc) < 5 do
{[e], [e|acc]}
else
[_ | tail] = Enum.reverse(acc)
next_acc = Enum.reverse(tail)
case Enum.reverse(acc) do
[@zun,@zun,@zun,@zun,@doko] -> {[@kiyoshi,e],[e | next_acc]}
_ -> {[e],[e | next_acc]}
end
end
end)
end
end
順に説明します
zundoko
無限長のリストを作成します。
randomにズン
,ドコ
を吐き出し続けることが可能です。
def zundoko do
Stream.repeatedly(fn -> Enum.random([@zun, @doko]) end)
end
個別に実行すると次のようになります。
iex(67)> Zundoko.zundoko |> Enum.take(5)
["ドコ ", "ズン ", "ズン ", "ズン ", "ズン "]
iex(68)> Zundoko.zundoko |> Enum.take(5)
["ドコ ", "ドコ ", "ドコ ", "ズン ", "ドコ "]
Enum.takeの地点で実行されます。
kiyoshi
無限長のリストを引数に取り内部的にwordを最大5wordバッファします。
バッファ内容に対して [@zun,@zun,@zun,@zun,@doko]
とマッチングしマッチしたらキ・ヨ・シ!
をリストに挿入します。
def kiyoshi(zundoko) do
zundoko |> Stream.transform([], fn e, acc ->
if Enum.count(acc) < 5 do
{[e], [e|acc]}
else
[_ | tail] = Enum.reverse(acc)
next_acc = Enum.reverse(tail)
case Enum.reverse(acc) do
[@zun,@zun,@zun,@zun,@doko] -> {[@kiyoshi,e],[e | next_acc]}
_ -> {[e],[e | next_acc]}
end
end
end)
end
Stream.transform(enum, acc, fun)
は以下のように引数を取ります。
- enum Stream(遅延評価リスト)
- acc(アキュームレータ) 処理全体を通して使用する一時保存変数です。今回はバッファとしてリストをもたせています
- fun (element,acc) 第一引数は上述enumの各要素、第二引数に上述のアキュームレータが来ます。
返却値としては返却するエレメントと次のアキュームレータの2要素のタプルとなります。