前々回
前回
前々回の続きで、遅延評価で囲む部分を、マクロで短縮してみた。
# $ crystal test7.cr # 遅延評価 class Delay(T) def initialize(init_v : T, &block : -> T) @func = block @flag = false @value = init_v end def force unless @flag ret = @func.call @value = ret.nil? ? raise("@func.call is nil. #{@func}") : ret @flag = true end @value end end # Bool 構造体にメソッドを追加 struct Bool def if(t, e) return t.responds_to?(:force) ? t.force : t if self e.responds_to?(:force) ? e.force : e end end # 短縮マクロ macro d_i(x) Delay(Int32).new(0){{{x}}} end macro d_ai(x) Delay(Array(Int32)).new([0]){{{x}}} end macro d_s(x) Delay(String).new(""){{{x}}} end struct Int # 階乗 def fact self.<=(0).if 1, d_i(self.pred.fact.*(self)) end # フィボナッチ def fib self.<=(1).if (self.==(0).if 0, 1), d_i(self.pred.fib.+(self.pred.pred.fib)) end # コラッツ (0 は無限ループ) def collatz self.==(1).if [1], d_ai(self.odd?.if d_ai(self.*(3).succ.collatz.unshift(self)), d_ai(self.tdiv(2).collatz.unshift(self))) end def hoge2 self.<=(0).if "1", d_s("yaahhhh") end end # 実行 puts 10.fact # => 3628800 puts (0..10).to_a.map &.fib # => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55] puts 3.collatz # => [3, 10, 5, 16, 8, 4, 2, 1] puts 3.hoge2 # => yaahhhh
コラッツをワンライナーで書けるのは嬉しい。
やはりマクロは Ruby と比べて、大きなアドバンテージになると思う。