ちょっぴりマクロで遊んだので備忘録。
はじめてなElixir(4)で div 演算子を Kernel.div じゃなく自分の定義した div 関数を呼ぶようにしたので、いい気になって / 演算子を置き換えます。
どうにも気になる / 演算子
代数としては一つの台集合上に演算が定義されててほしいじゃないですか。なので Elixir で(というか Erlang がそもそもなんでしょうが) / 演算子に整数突っ込んだ結果が浮動小数になるのは残念です。
iex(1)> 1
1
iex(2)> 1 * 1
1
iex(3)> 1 / 1
1.0
ってなんかヘンじゃありませんか? 同じ整数の台の上に居てほしいですよね、
マクロを使ってみる
ということで演算子を自分で定義してみました。
** これは大変危険な匂いがします。未来の自分を混乱させます **
defmodule Overload do
defmacro m / n do
quote do
Kernel.div(unquote(m), unquote(n))
end
end
end
これ、そのまま使っても何も起こりません。
iex(2)> 1/2
0.5
もともとの演算子を黙らせてから使います。
iex(3)> import Kernel, except: [/: 2]
Kernel
iex(4)> 1/2
** (CompileError) iex:4: undefined function //2
黙らせてしまったので / の演算自体ができなくなります。
iex(4)> import Overload
Overload
iex(5)> 1/2
0
iex(6)> 1/1
1
さっき定義したマクロを import するとそっちが有効になります。
マクロまで使ってプログラムすることはそんなにないだろうと思います。Scheme/Lisp は、quote を ' unquote を ` を使って積極的に使いたくなる文法にする、ってことをしてますが、Elixir はそうじゃないですし、こういうこともできるんだぐらいで。
参考文献
プログラミングElixir 本の 20.7 節を参照してます。