paiza.ioでelixir その185

# 概要
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

```

# 成果物

https://paiza.io/projects/mDnX6oUwU4ISBEs9P7xkyg


以上。