LoginSignup
15
9

More than 5 years have passed since last update.

ElixirのStreamでカウンタ付き無限ループ

Last updated at Posted at 2018-09-26

fukuoka.ex代表のpiacereです
今回もご覧いただいて、ありがとうございます:bow:

Elixirでdefと末尾再帰を使った、スタンダードなカウンタ付き無限ループのコラムを見たら、Streamでカウンタ付き無限ループを書きたくなったので、書いてみました:yum:

そういえば、こないだのStream版ズンドコキヨシと言い、ややStream芸人になりつつある…:sweat:


:stars::stars::stars: お知らせ:Elixirもくもく会(リモート参加OK、入門トラック有)を今月末に開催します :stars::stars::stars:

「fukuoka.ex#14:Elixir/Phoenixもくもく会~入門もあるよ」を9/28(金)に開催します

今回から「Zoomによるリモート参加」を正式に受け付けるようになりましたので、福岡以外の都心や地方からでも参加できます(申し込みいただいたら、追ってZoom URLをconnpassメールでお送りします)

また、これまではElixir/Phoenix経験者を対象とした、もくもく会オンリーでしたが、今回から、入門者トラックも併設し、fukuoka.exアドバイザーズ/キャストに質問できるようにアップグレードしました

お申込みはコチラから
https://fukuokaex.connpass.com/event/100659/
image.png

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そっくりだけど、何もしない役立たずが動く:stuck_out_tongue_winking_eye:

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コードを解釈できるようにしてみた:laughing:

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に戻ってくる(全く同じ表示なので、戻ったか一瞬分からず、とても紛らわしい)

p.s.「いいね」よろしくお願いします

よろしければ、ページ左上の image.pngimage.png のクリックをお願いしますー:bow:

15
9
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
9