概要
wsl(wsl2じゃない)で、elixirやってみた。
Cizen、やってみた。
参考にしたページ
手順
$ mix new testcizen
$ cd testcizen
defp deps do
[
{:cizen, "~> 0.14.1"}
]
end
$ mix deps.get
$ iex -S mix
サンプルコード
defmodule BorrowChopstick do
defstruct [:chopstick_id]
use Cizen.Request
defresponse LendChopstick, :request_id do
defstruct [:request_id]
end
end
defmodule ReturnChopstick do
defstruct [:chopstick_id]
end
defmodule Chopstick do
use Cizen.Automaton
defstruct []
alias Cizen.Effects.{Dispatch, Receive, Subscribe}
alias Cizen.{Event, Filter}
@impl true
def spawn(id, %__MODULE__{}) do
perform id, %Subscribe{
event_filter: Filter.any([
Filter.new(fn %Event{body: %BorrowChopstick{chopstick_id: ^id}} ->
true
end),
Filter.new(fn %Event{body: %ReturnChopstick{chopstick_id: ^id}} ->
true
end)
])
}
:available
end
@impl true
def yield(id, :available) do
received = perform id, %Receive{
event_filter: Filter.new(fn %Event{body: %BorrowChopstick{}} ->
true
end)
}
alias BorrowChopstick.LendChopstick
perform id, %Dispatch{
body: %LendChopstick{
request_id: received.id
}
}
:not_available
end
@impl true
def yield(id, :not_available) do
perform id, %Receive{
event_filter: Filter.new(fn %Event{body: %ReturnChopstick{}} ->
true
end)
}
:available
end
end
defmodule Philosopher do
use Cizen.Automaton
defstruct [:name, :left_chopstick, :right_chopstick]
alias Cizen.Effects.{Request, Dispatch}
@impl true
def spawn(_id, struct) do
{:hungry, struct}
end
@impl true
def yield(id, {:hungry, struct}) do
%__MODULE__{
name: name,
left_chopstick: left_chopstick,
right_chopstick: right_chopstick
} = struct
IO.puts("#{name} is hungry.")
perform id, %Request{
body: %BorrowChopstick{
chopstick_id: left_chopstick
}
}
IO.puts("#{name} has a chopstick in their left hand.")
perform id, %Request{
body: %BorrowChopstick{
chopstick_id: right_chopstick
}
}
IO.puts("#{name} has chopstics in both hands.")
{:eating, struct}
end
@impl true
def yield(id, {:eating, struct}) do
%__MODULE__{
name: name,
left_chopstick: left_chopstick,
right_chopstick: right_chopstick
} = struct
IO.puts("#{name} is eating.")
perform id, %Dispatch{
body: %ReturnChopstick{
chopstick_id: left_chopstick
}
}
perform id, %Dispatch{
body: %ReturnChopstick{
chopstick_id: right_chopstick
}
}
{:hungry, struct}
end
end
defmodule Dining do
use Cizen.Effectful
alias Cizen.Effects.{All, Start}
def run do
handle fn id ->
chopstick_1 = perform id, %Start{saga: %Chopstick{}}
chopstick_2 = perform id, %Start{saga: %Chopstick{}}
chopstick_3 = perform id, %Start{saga: %Chopstick{}}
chopstick_4 = perform id, %Start{saga: %Chopstick{}}
chopstick_5 = perform id, %Start{saga: %Chopstick{}}
philosophers = [
%Philosopher{
name: "Plato",
left_chopstick: chopstick_1,
right_chopstick: chopstick_2
},
%Philosopher{
name: "Konfuzius",
left_chopstick: chopstick_2,
right_chopstick: chopstick_3
},
%Philosopher{
name: "Socrates",
left_chopstick: chopstick_3,
right_chopstick: chopstick_4
},
%Philosopher{
name: "Voltaire",
left_chopstick: chopstick_4,
right_chopstick: chopstick_5
},
%Philosopher{
name: "Descartes",
left_chopstick: chopstick_5,
right_chopstick: chopstick_1
}
]
perform id, %All{
effects: Enum.map(philosophers, &(%Start{saga: &1}))
}
receive do
_ ->
:ok
end
end
end
end
実行結果
Interactive Elixir (1.13.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Dining.run
Plato is hungry.
Konfuzius is hungry.
Socrates is hungry.
Voltaire is hungry.
Descartes is hungry.
Plato has a chopstick in their left hand.
Konfuzius has a chopstick in their left hand.
Socrates has a chopstick in their left hand.
Voltaire has a chopstick in their left hand.
Descartes has a chopstick in their left hand.
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
(l)oaded (v)ersion (k)ill (D)b-tables (d)istribution
a
以上。