関数を返す関数っていつ使うの

Route 477(2008-01-10)
釈迦に説法のような気もしますが、力尽きていらっしゃるようなので。
まず普通にstring_ltを実装してみます。で、これの文字列の比較部分だけを変更して、その他の部分を共有する方法について考えてみます。

def string_lt(*strs)
  (1 ... strs.size).each do |i|
    return false unless strs[i - 1] < strs[i]
  end
  true
end

p string_lt('a', 'b', 'c') # => true

Rubyではブロックを使ってそのメソッドに特化の部分をメソッド外部から与えることができます。個人的にはこれが一番Rubyらしいアプローチだと思います。

def string_comparer(*strs, &test)
  (1 ... strs.size).each do |i|
    return false unless test[strs[i - 1], strs[i]]
  end
  true
end

def string_lt(*strs)
  string_comparer(*strs) {|s1, s2| s1 < s2 }
end

p string_lt('a', 'b', 'c') # => true

関数を生成する関数じゃないといやだ!という人は、lambdaを使って似たようなことができます。

def make_string_comparer(&test)
  lambda do |*strs|
    (1 ... strs.size).each do |i|
      return false unless test[strs[i - 1], strs[i]]
    end
    true
  end
end

string_lt = make_string_comparer {|s1, s2| s1 < s2 }

p string_lt['a', 'b', 'c'] # => true

関数型言語を使うようになってから、こんな感じの高階関数が好きになりました。ぜひ関数型言語を学ぼう! 普段あんまり使わなくても得られるものはあります。