Skip to content

Instantly share code, notes, and snippets.

@mizchi
Created May 27, 2015 01:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mizchi/d712c1d36fa95177b96c to your computer and use it in GitHub Desktop.
Save mizchi/d712c1d36fa95177b96c to your computer and use it in GitHub Desktop.
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