Created
May 27, 2015 01:42
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Elixir/Mix入門 | |
## 概要 | |
- elixir / erlang vm へコンパイルされる言語。コンパイラ。 | |
- mix / elixirのプロジェクト管理ツール。elixirインストール時に入る | |
```diff:aaaaaa | |
aaaa | |
``` | |
## Install | |
Macで雑に入れた | |
``` | |
$ brew install elixir | |
``` | |
mix を使ってプロジェクトの雛形を生成する | |
``` | |
$ mix new elixir_playground --module Playground | |
$ cd elixir_playground | |
``` | |
## repl | |
``` | |
$ iex -S mix | |
``` | |
iex がrepl。-S mix でプロジェクトのモジュールとかに触れるようになる。 | |
## 実行 | |
編集してみる | |
lib/elixir_playground.ex | |
```elixir:foo.ex | |
defmodule Playground do | |
def start() do | |
IO.puts "foo" | |
end | |
end | |
``` | |
mix 経由で実行する | |
``` | |
$ mix run -e "Playground.start" | |
foo | |
``` | |
elixir foo.exでも実行はできるが、モジュール読み出しとかはうまくいかない。 | |
`mix test` で組み込みのユニットテストを実行出来る | |
## 外部モジュールを使う | |
[Hex](https://hex.pm/ "Hex") に登録されたものはversion直打ちでいける。applications で自分のプロジェクトにexport?するライブラリの名前を書く必要がある。 | |
今回は poison という JSONパーサを使ってみる。特にこれを選んだ理由はない。強いて言えば単機能っぽいので下手な挙動に引っ張られたりしなさそうではあった。 | |
```elixir | |
defmodule Playground.Mixfile do | |
use Mix.Project | |
# 略 | |
def application do | |
[applications: [:logger, :poison]] | |
end | |
defp deps do | |
[{:poison, "1.4.0"}] | |
end | |
end | |
``` | |
ソースを取得 | |
``` | |
$ mix deps.get | |
``` | |
poisonを使うためにこんなコードを書いた。ほとんどexampleのまま。 | |
```elixir | |
defmodule Person do | |
defstruct [:name, :age] | |
end | |
defmodule Playground do | |
def start() do | |
IO.puts inspect Poison.decode!(~s({"name": "Devin Torres", "age": 27}), as: Person) | |
end | |
end | |
``` | |
hexに登録してされていなくてもgithub記法みたいなのがある。Erlangのモジュールも呼べる。 | |
``` | |
defp deps do | |
[{:elixir_v8, github: "le0pard/elixir_v8"}] | |
end | |
``` | |
(V8をソースからビルドするのですごく遅い) | |
elixirのモジュールはそのまま呼べるが、elixirからerlangのモジュールを呼びたい場合、コロンから始める必要があった。 | |
``` | |
{ok, VM} = :jerlang_v8:start_vm() | |
:erlang_v8:eval(vm, "function sum(a, b) { return a + b }") | |
``` | |
なんかErlangへの参照とatomの記法被ってる気がするんだけど、それはどうなんだろう… | |
## Map型 | |
``` | |
iex(3)> obj = %{} | |
%{} | |
iex(4)> Dict.put obj, :a, 1 | |
%{a: 1} | |
iex(5)> obj | |
%{} | |
``` | |
Dict.put は Immutable | |
# Agentを使う | |
Elixirで扱うデータは基本的に普遍データ構造なのだが、見た目上副作用が起こせるようにみえる。 | |
``` | |
a = 1 | |
a = 2 | |
``` | |
このコードは通る。が、内部的にはa0, a1 とコンパイルされているようだ。シャドウイングという挙動。 | |
で、実際に状態を表現するのはどうするかというと、erlang的にはgen_serverという機能でサーバーを立てるらしいのだが、elixirにはそれをラップしたAgentという機能がある。 | |
```elixir | |
defmodule Playground do | |
def start() do | |
{:ok, agent} = Agent.start_link fn -> %{} end | |
Agent.update(agent, fn state -> Dict.put(state, :a, 1) end) | |
IO.inspect Agent.get(agent, fn i -> i end) | |
Agent.update(agent, fn state -> Dict.put(state, :b, 2) end) | |
IO.inspect Agent.get(agent, fn %{b: b} -> b end) | |
end | |
end | |
``` | |
``` | |
$ mix run -e "Playground.start" | |
%{a: 1} | |
2 | |
``` | |
二回目のinspectはなんとなくパターンマッチングしてみたくなったのでbだけ取り出した。 | |
## GenServer | |
ビヘイビアとは、Erlang/OTPの恩恵を受けるための実装すべきインターフェースを指定するもの。 | |
GenServerビヘイビアを使ってStackを表現する | |
```ruby | |
defmodule Stack do | |
use GenServer | |
def handle_call(:pop, _from, [h|t]) do | |
{:reply, h, t} | |
end | |
def handle_cast({:push, item}, state) do | |
{:noreply, [item|state]} | |
end | |
def handle_cast({:replace, next}, _state) do | |
{:noreply, next} | |
end | |
end | |
defmodule Playground do | |
def start() do | |
{:ok, pid} = GenServer.start_link(Stack, [:hello]) | |
IO.inspect GenServer.call(pid, :pop) | |
IO.inspect GenServer.cast(pid, {:push, :world}) | |
IO.inspect GenServer.cast(pid, {:replace, [:hoge]}) | |
IO.inspect GenServer.call(pid, :pop) | |
end | |
end | |
``` | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment