コラッツ予想がとけたらいいな2

自分の考察を書いていきます。

Crystal をやってみた その6(短縮マクロ)

前々回

前回


前々回の続きで、遅延評価で囲む部分を、マクロで短縮してみた。


# $ 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 と比べて、大きなアドバンテージになると思う。