fukuoka.ex代表のpiacereです
今回もご覧いただいて、ありがとうございます
Elixirでdefと末尾再帰を使った、スタンダードなカウンタ付き無限ループのコラムを見たら、Streamでカウンタ付き無限ループを書きたくなったので、書いてみました
そういえば、こないだのStream版ズンドコキヨシと言い、ややStream芸人になりつつある…
お知らせ:Elixirもくもく会(リモート参加OK、入門トラック有)を今月末に開催します
「fukuoka.ex#14:Elixir/Phoenixもくもく会~入門もあるよ」を9/28(金)に開催します
今回から「Zoomによるリモート参加」を正式に受け付けるようになりましたので、福岡以外の都心や地方からでも参加できます(申し込みいただいたら、追ってZoom URLをconnpassメールでお送りします)
また、これまではElixir/Phoenix経験者を対象とした、もくもく会オンリーでしたが、今回から、入門者トラックも併設し、fukuoka.exアドバイザーズ/キャストに質問できるようにアップグレードしました
お申込みはコチラから
https://fukuokaex.connpass.com/event/100659/
Streamでカウンタ付き無限ループ
Streamでカウンタ付き無限ループを実装するには、Stream.iterateが便利
start = 0
count_up = 1
sleep_msec = 1000
Stream.iterate( start, &( &1 + count_up ) ) |>
Enum.map( fn count ->
IO.puts( "count => #{ count }, count_up => #{ count_up }" )
:timer.sleep( sleep_msec )
end )
ね?けっこうカンタンに組めるでしょ?
iexで上記を実行しても良いし、defで関数化してもOK
実行すると、こんな感じで、カウンタ付きの無限ループとなる(Ctrl+cでストップすると、iex毎、抜けてしまうが、止め方がそれしか無い)
count => 0, count_up => 1
(1秒待つ)
count => 1, count_up => 1
(1秒待つ)
count => 2, count_up => 1
(1秒待つ)
count => 3, count_up => 1
(1秒待つ)
…
カウンタ付き無限ループで、iexもどきを作る
IO.getsを併用すると、ユーザ入力待ちループも作れるので、iexのようなものを作ることもできる
start = 1
count_up = 1
Stream.iterate( start, &( &1 + count_up ) ) |>
Enum.map( fn count ->
input = IO.gets( "iex(#{ count })> " )
IO.write( "none exec #{ input }" )
end )
実行すると、見た目はiexそっくりだけど、何もしない役立たずが動く
iex(1)> IO.puts( "hello" )
none exec IO.puts( "hello" )
iex(2)> IO.inspect( %{ "key1" => "v1", "key2" => "v2" } )
none exec IO.inspect( %{ "key1" => "v1", "key2" => "v2" } )
iex(3)>
ここまで来ておいて折角なので、Elixirコードを解釈できるようにしてみた
start = 1
count_up = 1
Stream.iterate( start, &( &1 + count_up ) ) |>
Enum.map( fn count ->
input = IO.gets( "iex(#{ count })> " )
Code.eval_string( input )
end )
まるでiexのように、Elixirコード断片を実行できて、ちょっとだけ役立たずでは無くなる
iex(1)> IO.puts( "hello" )
hello
iex(2)> IO.inspect( %{ "key1" => "v1", "key2" => "v2" } )
%{"key1" => "v1", "key2" => "v2"}
iex(3)> [ 1, 2, 3 ] |> Enum.map( &( &1 + 1 ) ) |> IO.inspect
[2, 3, 4]
ちなみに、エラーになるようなコードを書くと、無限ループは終了し、元のiexに戻ってくる(全く同じ表示なので、戻ったか一瞬分からず、とても紛らわしい)