@udzura さま(〃l _ l)?? さっちゃんですヾ(〃l _ l)ノ゙ (憤怒の相直されました(〃l _ l)
Elixir Advent Calendar 2013 14日目です。昨日はElixir - Sigil大好き!一番好きな機能です。 - Qiita [キータ]でした。あーRubyの。独自定義出来るのか、ふうむ。
最近Elixir書いてない……(〃l _ l) 最近はnode.jsです。Ruby, PHP, JavaScriptを回し使ってます。
と思ったら、WindowsでもElixirのpre-compiledが手に入る様に成ってますね。隔世の感です。ErlangもElixirもWindowsで不便しませんねえ……。Elixir使ふ度にVMをひとつあげてたのですけれども、それも変わりますね。日用Elixir。
Erlang VMにRubyの見栄えを被せてClojureの体に作りなおしたらElixirな感じ。
Macro
JavaScriptはmacroの無いLispと云った感です。Function.prototype.bindもできましたし、まあ手加減して、macroの無いLispだとくらいは言ってあげてもいいんじゃないでせうか。
一方Rubyは、
Ruby is a language designed in the following steps:なのでmacroは有りません。代わりにOOに則ったrefletionを使ひます。* take a simple lisp language (like one prior to CL).
* remove macros, s-expression.
* add simple object system (much simpler than CLOS).
* add blocks, inspired by higher order functions.
* add methods found in Smalltalk.
* add functionality found in Perl (in OO way).
Elixirはmacroだ。macroを使ふ。macroの作り方は、Elixirの構文木を知る方法もあるが、quoteとunquoteをぶつけるのをよく見る。
Elixirの構文木を知りたければ、iexでquoteしてみれば好い。然して構文木を直接操作するのは余り得策ではない事が解る。似た式の列でも、少し変えると大きく木が変わる事が有る。
macroでDSLを作る例は、公式blogに有る。
cf. Building a Web Framework. Part I - Elixir http://elixir-lang.org/blog/2012/04/21/hello-macros/
Mnesia向けのDSL実装も例として読める。
cf. amnesia/lib/amnesia.ex at master ・ meh/amnesia https://github.com/meh/amnesia/blob/master/lib/amnesia.ex
スゴイpattern match。スゴイ。なんでもできそう(かなり)。
Protocol
protocolが何のためにあるかわからない感あった。実装持てないし。多態性 (polymorphism) と言われても、pattern matchは? と云ふ感じで居たが、然ふではなかった。
jsでは此うだ。或る二つの未知のobject a, bが有り、共にm()と云ふmethodを呼び出せれば多態と言へる。実装するには此う (型付けはされないので継承は不要だ)。
function A() { } A.prototype.m = function () { }; function B() { } B.prototype.m = function () { }; var a = new A(), b = new B(); a.m(); b.m();
Pythonの第一引数selfや、D言語のUFCS (Universal Function Call Syntax) や、jsのFunction.prototype.apply (Function.prototype.call) の例を持ち出せばいいが、method呼び出しの多く (「多く」は卑怯なわたしの予防線であり、実は「全部」ではないかと思ってゐる) は暗默の引数と解釈できる。a.m()はm(a)と解釈できる。m(a)とm(b)は全く別の実装を参照する。この二つの実装は無関係でありうる。無関係でありうるのが多態の利点だと言へる。
ここまで言葉にすれば、protocolも同じだと解る。前述のjsと同等の例を書けば、
defprotocol M do def m(obj) end defrecord A, [] defimple M, for: A do def m(obj) do end end defrecord B, [] defimple M, for: B do def m(obj) do end end a = A.new b = B.new import M m(a) m(b)
全く同じだと云ふのが解る。此の解釈で正しければ、漸く腑に落ちたところだ。
で、Behaviorってなんなんだらうねえ……(〃l _ l)
因みに暗默の引数の機構はElixirにも有り、pipeline演算子 |> と云ふF#由来の文法だ。ますますUFCSっぽい。
Binary構文
Erlang由来だが(〃l _ l)
Elixir (Erlang) のpattern matchはすごい。Rubyやjsに同等のものは無いが、関数定義に於けるpattern matchは一種の多態性 (多相性) だから、Rubyやjsは構文的に多態の一部を諦めてゐることになる。JavaやC#はmethodの多重定義ができる訳だ。そこでHaxeの構造的部分型 (structual subtyping) 等も見るに、pattern matchは型systemの一部だと云ふ事が解る。Rubyやjsはduck typingだからpatter matchが無いのではなく、専用の構文が無く、手動でやる事になってゐるだけだ。ほんとうは関数が複数の引数をとれるのはpattern matchの一部だとするべきなのかもしれなかった。或る構造をもったdataから、その構造を比較したり部分を取り出したりするのがpattern matchの力だ。だから此の型systemの一部は、型systemを実装側から利用する技術のひとつだといったほうがよかったかもしれなかった。もちろん他の解釈はあるはずだ。
(と思ったら、いちおうRubyに然ふ云ふlibraryは有るらしい。cf. kstephens/multimethod https://github.com/kstephens/multimethod cf. psantacl/ruby-multimethods https://github.com/psantacl/ruby-multimethods )
Elixirのbinary構文は、binaryに、直接に構造を持ち込める。因みにElixirの文字列はただのbinaryであり、区別は無い (因みにElixirの「文字列」には二種類有り、double quoteの"ab" = <<?a, ?b>>
且つ"ab" = <<"a", "b">>
であり此れはbite列、single quoteの'ab' = [?a, ?b]
であり此れは文字のList。ただsingle quoteの方を使ってゐるのは見た事が無い。因みに?a = 97
)。
例へば文字列 "binary" の最初の3byteを分離したいとすると、
<<f::[binary, size(3)], _rest::binary>> = "binary"
で f = "bin", r = "ary" と成る。binary構文は入れ子にもできる。
<< <<?b, f1::integer, f2::[binary, size(2)]>>, _rest::binary>> = "binary"
等、byte列をcasualに分解できる。逆に組み立てる事もできる。
pattern matchと云へば、Egison http://www.egison.org/index-j.html も観察してみたいね。
少し書き過ぎました。
おじいさん、spawnやOTPの事は2000年前に食べたでしょ(〃l _ l) (←いいかげん習得しろ
明日は k1complete さんです。