プログラミング Elixir 確認メモ (2)
続
内包表記のやつ、ちょっとカンニングしたやつを読んでみます。コードが以下。
for a <- range, b <- range, a <= b, a*b <= n, do: a*b
これは素数ではない数の数え上げになっているはず。range が [1, 2, 3, 4, 5] とすると以下が戻った?
> n = 5
5
> range = MyList.span(1, 5)
[1, 2, 3, 4, 5]
> for a <- range, b <- range, a <= b, a*b <= n, do: a*b
[1, 2, 3, 4, 5, 4]
なんか勘違いしている風。と思ったら span(2, 5) だった。
> range = MyList.span(2, n)
[2, 3, 4, 5]
> (for a <- range, b <- range, a <= b, a*b <= n, do: a*b)
[4]
これだと 2*2 だけが残る。
OrganizingAProject-1
テキストおさらい。色々云々してると config あたりで躓くなど。確認したら 1.16 入れてるし。
テーブル整形のあたり
コード確認必要ですね。あと Excercise の回答が以下で公開とのこと。
実装が以下です。
defmodule Issues.TableFormatter do
import Enum, only: [ each: 2, map: 2, map_join: 3, max: 1]
def print_table_for_columns(rows, headers) do
with data_by_columns = split_into_columns(rows, headers),
columns_width = widths_of(data_by_columns),
format = format_for(columns_width)
do
puts_one_line_in_columns(headers, format)
IO.puts(separator(columns_width))
puts_in_columns(data_by_columns, format)
end
end
def split_into_columns(rows, headers) do
for header <- headers do
for row <- rows, do: printable(row[header])
end
end
def printable(str) when is_binary(str), do: str
def printable(str), do: to_string(str)
def widths_of(columns) do
for column <- columns, do: column |> map(&String.length/1) |> max
end
def format_for(column_widths) do
map_join(column_widths, " | ", fn width -> "~-#{width}s" end) <> "~n"
end
def separator(column_widths) do
map_join(column_widths, "-+-", fn width -> List.duplicate("-", width) end)
end
def puts_in_columns(data_by_columns, format) do
data_by_columns
|> List.zip
|> map(&Tuple.to_list/1)
|> each(&puts_one_line_in_columns(&1, format))
end
def puts_one_line_in_columns(fields, format) do
:io.format(format, fields)
end
end
テスト見れば大体わかりますが以下の理解が微妙。
data_by_columns
|> List.zip
|> map(&Tuple.to_list/1)
|> each(&puts_one_line_in_columns(&1, format))
data_by_columns は以下なリスト? として
[
["r1 c1", "r2 c1", "r3 c1", "r4 c1"],
["r1 c2", "r2 c2", "r3 c2", "r4++c2"],
["r1+++c4", "r2 c4", "r3 c4", "r4 c4"]
]
zip したらこうなるのか。
[
{"r1 c1", "r1 c2", "r1+++c4"},
{"r2 c1", "r2 c2", "r2 c4"},
{"r3 c1", "r3 c2", "r3 c4"},
{"r4 c1", "r4++c2", "r4 c4"}
]
確かに出力される順の並びになってますね。で次は要素な tuple を List に変換してるはず。最後に要素を出力、なのか成程。
複数プロセス
15.2 節の chain.exs については確認メモを控えます。
code_to_run は無名関数で Chain.counter に pid が渡される形
Enum.reduce(1..n, self(), code_to_run) は 1 から n まで数えあげしつつ code_to_run を呼び出す
最初の第二引数は self() です
以降は code_to_run が戻す pid が渡されます
最終的に一番最後に spawn された pid が last に渡されます
で、コメントの通りで最後に作ったプロセスに 0 を渡して起動
最後に起動されるはずの self() で定義されてる receive が最終結果を受け取る
テキストにあるように実行してみます。
# elixir -r chain.exs -e "Chain.run(10)"
{1973, "Result is 10"}
# elixir -r chain.exs -e "Chain.run(100)"
{2112, "Result is 100"}
# elixir -r chain.exs -e "Chain.run(1_000)"
{3514, "Result is 1000"}
# elixir -r chain.exs -e "Chain.run(10_000)"
{18652, "Result is 10000"}
# elixir -r chain.exs -e "Chain.run(400_000)"
01:50:51.625 [error] Too many processes
** (SystemLimitError) a system limit has been reached
:erlang.spawn(Chain, :counter, [#PID<0.262246.0>])
chain.exs:11: anonymous fn/2 in Chain.create_processes/1
(elixir 1.16.1) lib/enum.ex:4391: Enum.reduce_range/5
chain.exs:14: Chain.create_processes/1
(stdlib 5.2) timer.erl:312: :timer.tc/4
chain.exs:25: Chain.run/1
nofile:1: (file)
# elixir --erl "+P 1000000" -r chain.exs -e "Chain.run(400_000)"
{788726, "Result is 400000"}
# elixir --erl "+P 1000000" -r chain.exs -e "Chain.run(1_000_000)"
{2699493, "Result is 1000000"}
これは強力。某所にて並列処理で大変だった記憶があるのですがこれは凄い。
WorkingWIthMultipleProcess-2
以下をでっち上げました。
defmodule WorkingWithMultipleProcess2 do
def send_token do
receive do
{sender, msg} ->
send sender, { :ok, "#{msg}" }
end
end
end
pid1 = spawn(WorkingWithMultipleProcess2, :send_token, [])
send pid1, {self(), "fred"}
pid2 = spawn(WorkingWithMultipleProcess2, :send_token, [])
send pid2, {self(), "betty"}
receive do
{:ok, message} ->
IO.puts message
end
receive do
{:ok, message} ->
IO.puts message
end
これだと必ずしも順番に出力されないことを確認。順序を決定的にするには
send_token で繰り返し
同じプロセスに send
という形で大丈夫みたいでした。
defmodule WorkingWithMultipleProcess2 do
def send_token do
receive do
{sender, msg} ->
send sender, { :ok, "#{msg}" }
send_token()
end
# 中略
pid1 = spawn(WorkingWithMultipleProcess2, :send_token, [])
send pid1, {self(), "fred"}
send pid1, {self(), "betty"}
この記事が気に入ったらサポートをしてみませんか?