概要
paiza.ioでelixirやってみた。
練習問題やってみた。
練習問題
Forthインタープリタを書け。
forthで数9を4個つかって1から15までの数を表す式を実行せよ。
Streamを使え。
サンプルコード
defmodule Forth do
def start_link do
Agent.start_link(fn ->
[]
end, name: __MODULE__)
end
def add do
Agent.update(__MODULE__, fn stack ->
po = Enum.count(stack) - 1
top = Stream.transform(stack, 0, fn i, acc ->
if acc == po, do: {[i], acc + 1}, else: {[], acc + 1}
end)
|> Enum.to_list
|> Enum.at(0)
po = po - 1
stack = Stream.transform(stack, 0, fn i, acc ->
if acc == po, do: {[i + top], acc + 1}, else: {[i], acc + 1}
end)
|> Enum.to_list
po = po + 1
Stream.take(stack, po)
|> Enum.to_list
end)
end
def sub do
Agent.update(__MODULE__, fn stack ->
po = Enum.count(stack) - 1
top = Stream.transform(stack, 0, fn i, acc ->
if acc == po, do: {[i], acc + 1}, else: {[], acc + 1}
end)
|> Enum.to_list
|> Enum.at(0)
po = po - 1
stack = Stream.transform(stack, 0, fn i, acc ->
if acc == po, do: {[i - top], acc + 1}, else: {[i], acc + 1}
end)
|> Enum.to_list
po = po + 1
Stream.take(stack, po)
|> Enum.to_list
end)
end
def mul do
Agent.update(__MODULE__, fn stack ->
po = Enum.count(stack) - 1
top = Stream.transform(stack, 0, fn i, acc ->
if acc == po, do: {[i], acc + 1}, else: {[], acc + 1}
end)
|> Enum.to_list
|> Enum.at(0)
po = po - 1
stack = Stream.transform(stack, 0, fn i, acc ->
if acc == po, do: {[i * top], acc + 1}, else: {[i], acc + 1}
end)
|> Enum.to_list
po = po + 1
Stream.take(stack, po)
|> Enum.to_list
end)
end
def div do
Agent.update(__MODULE__, fn stack ->
po = Enum.count(stack) - 1
top = Stream.transform(stack, 0, fn i, acc ->
if acc == po, do: {[i], acc + 1}, else: {[], acc + 1}
end)
|> Enum.to_list
|> Enum.at(0)
po = po - 1
stack = Stream.transform(stack, 0, fn i, acc ->
if acc == po, do: {[i / top], acc + 1}, else: {[i], acc + 1}
end)
|> Enum.to_list
po = po + 1
Stream.take(stack, po)
|> Enum.to_list
end)
end
def dup do
Agent.update(__MODULE__, fn stack ->
po = Enum.count(stack) - 1
top = Stream.transform(stack, 0, fn i, acc ->
if acc == po, do: {[i], acc + 1}, else: {[], acc + 1}
end)
|> Enum.to_list
|> Enum.at(0)
Stream.concat(stack, [top])
|> Enum.to_list
end)
end
def drop do
Agent.update(__MODULE__, fn stack ->
po = Enum.count(stack) - 1
Stream.take(stack, po)
|> Enum.to_list
end)
end
def get do
Agent.get(__MODULE__, fn stack ->
po = Enum.count(stack) - 1
Stream.transform(stack, 0, fn i, acc ->
if acc == po, do: {[i], acc + 1}, else: {[], acc + 1}
end)
|> Enum.to_list
|> Enum.at(0)
end)
end
def push(n) do
Agent.update(__MODULE__, fn stack ->
{v, _} = Integer.parse(n)
Stream.concat(stack, [v])
|> Enum.to_list
end)
end
end
defmodule Main do
def run(str) do
Enum.map(String.split(str, " "), fn s ->
cond do
s == "+" ->
Forth.add
s == "-" ->
Forth.sub
s == "*" ->
Forth.mul
s == "/" ->
Forth.div
s == "dup" ->
Forth.dup
s == "drop" ->
Forth.drop
s == "." ->
IO.inspect Forth.get
true ->
Forth.push(s)
end
end)
end
end
Forth.start_link
Main.run("9 9 - 9 9 / .")
Main.run("9 9 / 9 9 / + .")
Main.run("9 9 + 9 + 9 / .")
Main.run("9 9 9 + 9 / dup + .")
Main.run("9 9 9 + 9 / dup + - .")
Main.run("9 dup 9 + 9 + 9 / - .")
Main.run("9 9 9 + 9 / - .")
Main.run("9 9 9 drop 9 / - .")
Main.run("9 9 - 9 * 9 + .")
Main.run("9 9 / 9 dup 9 / + .")
Main.run("9 9 9 + 9 / + .")
Main.run("9 dup 9 9 + + 9 / + .")
Main.run("9 9 9 + 9 / dup + + .")
Main.run("9 dup 9 9 + 9 / dup + - + .")
Main.run("9 dup dup 9 + 9 + 9 / - + .")
実行結果
1.0
2.0
3.0
4.0
5.0
6.0
7.0
8.0
9
10.0
11.0
12.0
13.0
14.0
15.0
成果物
以上。