1.9K Views
May 27, 19
スライド概要
Clojure使い(Clojurian)としてElixirに入門した話です(*> ᴗ •*)ゞ
「楽しく楽にcoolにsmartに」を理想とするprogrammer/philosopher/liberalist/realist。 好きな言語はClojure, Haskell, Python, English, français, русский。 読書、プログラミング、語学、法学、数学が大好き! イルカと海も大好き🐬
Clojurian Elixir
lagénorhynque (defprofile lagénorhynque :id @lagenorhynque :reading "/laʒenɔʁɛ̃ k/" :aliases [" "] :languages [Clojure Haskell English français] :interests [programming language-learning law mathematics] :commits ["github.com/lagenorhynque/duct.module.pedestal"] :contributes ["github.com/japan-clojurians/clojure-site-ja"])
6 Lisp Clojure : (*> ᴗ •*) REST API cf. BOOTH https://booth.pm/ja/items/1317263
1. Clojure 2. Elixir 3. Clojure 4. Clojure Elixir
Clojure Elixir
Clojure : Rich Hickey : 2007 : 1.10.0 : Java VM (JVM) Lisp /
Elixir : José Valim : 2011 : 1.8.2 : Erlang VM (EVM; BEAM) Ruby Clojure
e.g. 20 Clojure ;; REPL (read-eval-print loop) user> (->> (iterate (fn [[a b]] [b (+ a b)]) [0 1]) (map first) (take 20)) (0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181)
Elixir # IEx (Interactive Elixir) iex(1)> Stream.iterate({0, 1}, fn {a, b} -> {b, a+b} end) |> ...(1)> Stream.map(&elem(&1, 0)) |> ...(1)> Enum.take(20) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181] # iex(2)> Stream.unfold({0, 1}, fn {a, b} -> {a, {b, a+b}} end) |> ...(2)> Enum.take(20) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
Elixir à la Clojure?
cf. : Programming Clojure, Third Edition
cf. : Programming Elixir ≥ 1.6
7 7 Ruby, Io, Prolog, Scala, Erlang, Clojure, Haskell
Seven More Languages in Seven Weeks Lua, Factor, Elixir, Elm, Julia, MiniKanren, Idris
Seven Concurrency Models in Seven Weeks Chapter 3, 4, 6: Clojure Chapter 5: Elixir
Mastering Clojure Macros
Metaprogramming Elixir
Elixir Erlang/OTP Elixir
Elixir Getting Started
Erlang/Elixir Syntax: A Crash Course
Clojure
Clojure
user> '(1 2 3)
(1 2 3)
user> [1 2 3]
[1 2 3]
user> {:a 1 :b 2 :c 3}
{:a 1, :b 2, :c 3}
;
※
;
;
Elixir
iex(2)> [1, 2, 3]
[1, 2, 3]
iex(3)> {1, 2, 3}
{1, 2, 3}
iex(4)> %{a: 1, b: 2, c: 3}
%{a: 1, b: 2, c: 3}
cf.
#
#
#
(Clojure
)
/
Clojure
user> (ns example)
nil
example> (defn square [x]
(* x x))
#'example/square
example> (in-ns 'user)
#namespace[user]
user>
;
;
`example`
`square`
;
`user`
Elixir
iex(5)> defmodule Example do #
`Example`
...(5)>
def square(x) do
#
`square`
...(5)>
x * x
...(5)>
end
...(5)> end
{:module, Example,
<<70, 79, 82, 49, 0, 0, 4, 100, 66, 69, 65, 77, 65, 116, 85, 56,
0, 0, 0, 14, 14, 69, 108, 105, 120, 105, 114, 46, 69, 120, 97,
101, 8, 95, 95, 105, 110, 102, 111, 95, ...>>, {:square, 1}}
Clojure user> (example/square 3) ; `example` `square` 9 user> (map example/square (range 1 (inc 10))) (1 4 9 16 25 36 49 64 81 100) Elixir iex(6)> Example.square(3) # `Example` `square` 9 iex(7)> Enum.map(1..10, &Example.square/1) [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
/ Clojure user> (map (fn [x] (* x x)) (range 1 (inc 10))) (1 4 9 16 25 36 49 64 81 100) user> (map #(* % %) (range 1 (inc 10))) (1 4 9 16 25 36 49 64 81 100) Elixir iex(8)> Enum.map(1..10, fn(x) -> x * x end) [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] iex(8)> Enum.map(1..10, &(&1 * &1)) [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>> (threading macro) vs |> (pipe operator) Clojure user> (->> (range 1 (inc 10)) (map #(* % %)) (filter odd?) (apply +)) 165 Elixir iex(9)> require Integer Integer iex(10)> 1..10 |> ...(10)> Enum.map(&(&1 * &1)) |> ...(10)> Enum.filter(&Integer.is_odd/1) |> ...(10)> Enum.sum 165 cf.
Clojure
user> (defprotocol Shape
(area [x]))
Shape
;
;
`Shape`
`area`
Elixir
iex(1)> defprotocol Shape do #
`Shape`
...(1)>
def area(x)
#
`area`
...(1)> end
{:module, Shape, ..., {:__protocol__, 1}}
/
Clojure
user> (defrecord Triangle [x h]
Shape
(area [{:keys [x h]}] (/
user.Triangle
user> (area (map->Triangle {:x 3
3
;
`Triangle`
;
(* x h) 2)))
:h 2}))
user> (defrecord Rectangle [x y] ;
Shape
;
(area [{:keys [x y]}] (* x y)))
user.Rectangle
user> (area (map->Rectangle {:x 2 :y 3}))
6
`Rectangle`
Elixir iex(2)> defmodule Triangle do # `Triangle` ...(2)> defstruct [:x, :h] ...(2)> end {:module, Triangle, ..., %Triangle{h: nil, x: nil}} iex(3)> defimpl Shape, for: Triangle do # ...(3)> def area(%Triangle{x: x, h: h}), do: x * h / 2 ...(3)> end {:module, Shape.Triangle, ..., {:__impl__, 1}} iex(4)> Shape.area(%Triangle{x: 3, h: 2}) 3.0 iex(5)> defmodule Rectangle do # `Rectangle` ...(5)> defstruct [:x, :y] ...(5)> end {:module, Rectangle, ..., %Rectangle{x: nil, y: nil}} iex(6)> defimpl Shape, for: Rectangle do # ...(6)> def area(%Rectangle{x: x, y: y}), do: x * y ...(6)> end {:module, Shape.Rectangle, ..., {:__impl__, 1}} iex(7)> Shape.area(%Rectangle{x: 2, y: 3}) 6
Clojure
user> (defrecord Circle [r]) ;
`Circle`
user.Circle
user> (area (map->Circle {:r 3}))
Execution error (IllegalArgumentException) at user/eval5412$fn$G
(REPL:47).
No implementation of method: :area of protocol: #'user/Shape fou
nd for class: user.Circle
Elixir
iex(8)> defmodule Circle do #
`Circle`
...(8)>
defstruct [:r]
...(8)> end
{:module, Circle, ..., %Circle{r: nil}}
iex(9)> Shape.area(%Circle{r: 3})
** (Protocol.UndefinedError) protocol Shape not implemented for
%Circle{r: 3}
iex:2: Shape.impl_for!/1
iex:3: Shape.area/1
Clojure
user> (extend-protocol Shape ;
Circle
(area [{:keys [r]}] (* Math/PI r r)))
nil
user> (area (map->Circle {:r 3}))
28.274333882308138
Elixir
iex(10)> defimpl Shape, for: Circle do #
...(10)>
def area(%Circle{r: r}), do: :math.pi() * r * r
...(10)> end
{:module, Shape.Circle, ..., {:__impl__, 1}}
iex(11)> Shape.area(%Circle{r: 3})
28.274333882308138
AST Clojure user> '(when (= 1 1) (println "Truthy!")) (when (= 1 1) (println "Truthy!")) ;; user> (quote (when (= 1 1) (println "Truthy!"))) (when (= 1 1) (println "Truthy!"))
Elixir
iex(1)> quote do
...(1)>
if 1 == 1 do
...(1)>
IO.puts "Truthy!"
...(1)>
end
...(1)> end
{:if, [context: Elixir, import: Kernel],
[
{:==, [context: Elixir, import: Kernel], [1, 1]},
[
do: {{:., [], [{:__aliases__, [alias: false], [:IO]}, :puts
]}, [],
["Truthy!"]}
]
]}
Clojure user> (ns example) nil example> (defmacro my-when-not [test & body] `(if ~test nil (do ~@body))) #'example/my-when-not example> (in-ns 'user) #namespace[user] user>
Elixir iex(2)> defmodule Example do ...(2)> defmacro my_unless(test, do: body) do ...(2)> quote do ...(2)> if unquote(test), do: nil, else: unquote(body) ...(2)> end ...(2)> end ...(2)> end {:module, Example, ..., {:my_unless, 2}}
Clojure user> (example/my-when-not (= 1 2) (println "Falsy!") 42) Falsy! 42 user> (example/my-when-not (= 1 1) (println "Falsy!") 42) nil
Elixir iex(3)> Example iex(4)> ...(4)> ...(4)> ...(4)> Falsy! 42 iex(5)> ...(5)> ...(5)> ...(5)> nil require Example Example.my_unless 1 == 2 do IO.puts "Falsy!" 42 end Example.my_unless 1 == 1 do IO.puts "Falsy!" 42 end
Clojure user> (macroexpand-1 ; 1 '(example/my-when-not (= 1 2) (println "Falsy!") 42)) (if (= 1 2) nil (do (println "Falsy!") 42))
Elixir iex(6)> quote do ...(6)> Example.my_unless 1 == 2 do ...(6)> IO.puts "Falsy!" ...(6)> 42 ...(6)> end ...(6)> end |> Macro.expand_once(__ENV__) |> ...(6)> Macro.to_string |> IO.puts if(1 == 2) do nil else IO.puts("Falsy!") 42 end :ok # # AST 1
Clojure
vs cf. Simple Made Easy (by Rich Hickey) REPL cf. REPL (REPL-driven development)
Elixirists Clojurians (?)
Further Reading
https://clojure.org : https://japanclojurians.github.io/clojure-site-ja/ https://elixir-lang.org : https://elixir-lang.jp Getting Started Erlang/Elixir Syntax: A Crash Course
Clojure 2 : Programming Clojure, Third Edition Elixir : Programming Elixir ≥ 1.6 7 7 Seven More Languages in Seven Weeks
Seven Concurrency Models in Seven Weeks Scala/Akka (Chapter 5) Mastering Clojure Macros Metaprogramming Elixir
Elixir Elixir Elixir Elixir Erlang/OTP
https://scrapbox.io/lagenorhynque/Elixir : lagenorhynque/programming-elixir