読者です 読者をやめる 読者になる 読者になる

ifもcaseも使わずに条件分岐

ruby

再び、λ楽しいよラムダの時間がやってまいりました。

true=λx.λy.x
false=λx.λy.y

そうすると、変数bがtrueかfalseをとるとして

b(0)(1)

とすると、bがtrueのとき0、falseのとき1を返します。

λで条件分岐ができた!

2009-04-09 - きしだのはてな


というわけで、λで条件分岐ができると聞いて、早速やってみた。
できれば、別関数を呼ばずにすませたい!ということで・・・

true/falseの代わりに関数を返すようにする

数字を比較した結果に応じて、値を返す。

#!/opt/local/bin/ruby1.9
class Fixnum
  @@tr = ->(x){ ->(y){ x }}
  @@fl = ->(x){ ->(y){ y }}
  
  def compare(n, arr)
    arr[self <=> n]
  end
  
  def ==(n)
    compare n, [@@tr, @@fl, @@fl]
  end
  
  def >(n)
    compare n, [@@fl, @@tr, @@fl]
  end

  def >=(n)
    compare n, [@@tr, @@tr, @@fl]
  end

  def <(n)
    compare n, [@@fl, @@fl, @@tr]
  end
  
  def <=(n)
    compare n, [@@tr, @@fl, @@tr]
  end  
end

puts (3 == 5).('foo').('bar') #=> bar
puts (3 == 3).('foo').('bar') #=> foo

puts (3 < 8).('foo').('bar') #=> foo
puts (3 > 8).('foo').('bar') #=> bar

できた。けど・・・
FloatやStringとか色々なところでこれを書くのは面倒。
true/falseを書き換えてしまおう。

true/falseが関数を返すようにする

といっても、true/falseはTrueClass, FalseClassのインスタンス
Classごと書き換えるのはちょっとなーってことで、ちょっと逃げてみた。

class Proc
  def [](n=nil)
    self.call n
  end
end

class TrueClass
  def [](n)
    ->(x){ ->(y){ x }}[n]
  end
end

class FalseClass
  def [](n)
    ->(x){ ->(y){ y }}[n]
  end
end

tr = ->{puts 'this is true.'}
fl = ->{puts 'this is false.'}
puts (('hoge' == 'hogo')[tr][fl]).() #=> this is false.

比較の結果返されたtrue, falseの[]メソッドを呼ぶと、それぞれを表す関数が返される。
呼び出しが()じゃなくなるのが汚いけど、()は定義できないみたい。

結論

ifもcaseも使わずに、条件分岐ができた!
もっと()だけで済ませられる方法とかないかなー。*1

*1:できればruby