Schemeを覚える3(高階関数)

http://d.hatena.ne.jp/hiro_nemu/20090208/1234104227
この日記のコメントでcametanさんに教えてもらい、高階関数Rubyクロージャ見たいな物ってことですんなり理解することができた。

今日もまた紫藤さんのページを参考に勉強する。今日は高階関数Rubyと比較しながらやってみたい。
Scheme 入門 8. 高階関数

sort

schemeの場合
> (sort '(10 9 3 8 2 1 5 4 7 6) <) ;リストの内容を昇順で並び替える
(1 2 3 4 5 6 7 8 9 10)
> (sort '(10 9 3 8 2 1 5 4 7 6) >) ;リストの内容を降順で並び替える
(10 9 8 7 6 5 4 3 2 1)
> (sort '(7883 9099 6729 2828 7754 4179 5340 2644 2958 2239) ;下2桁の昇順で並び替え(ぱくり)
      (lambda (x y) (< (modulo x 100) (modulo y 100))))
(2828 6729 2239 5340 2644 7754 2958 4179 7883 9099)
Rubyの場合
[10,9,3,8,2,1,5,4,7,6].sort #リストの内容を昇順で並び替える
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 実行結果
[10,9,3,8,2,1,5,4,7,6].sort{|x,y| y<=>x } #リストの内容を降順で並び替える
=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
 [7883,9099,6729,2828,7754,4179,5340,2644,2958,2239].sort{|x,y| (x % 100) <=> (y % 100) }
=> [2828, 6729, 2239, 5340, 2644, 7754, 2958, 4179, 7883, 9099]

と、RubyScheme結構似てるよね。Schemeの場合lambdaが無名関数を意味していてこいつをsortの2つ目の引数に渡しています。Rubyの場合、sortのあとにブロックを渡してます。(Rubyにもlambdaという構文もあるらしいけどこれは同じ意味かな。プログラミングRubyに書いていたような)

自前の高階関数

これも紫藤さんのページあったSchemeの場合の例。
member-if関数は、1つ目の引数に関数を、2つ目の引数にリストをとる。リストを1つずつ見ていきprocで渡した関数の結果がtrueになったらそれ以降のリストを返すという関数です。

> (define (member-if proc ls) ; member-if関数の定義 1つ目の引数には関数を、2つ目の引数にはリストをわたす
  (cond
   ((null? ls) #f)            ; lsがnullのときfalse
   ((proc (car ls)) ls)       ; 渡されたproc関数にリストの1つ目の要素を渡して実行、trueだったらlsを返す
   (else (member-if proc (cdr ls))))) ; 上記以外、再帰的にmember-ifを実行
> (member-if (lambda(x) (< 0 x)) '(-10 -5 -4 -3 0 10 20 30 40 50)) ; xの値が0より大きければtrueを返す無名関数を渡して実行
(10 20 30 40 50)

ここでは、member-if関数の1つ目の引数に「(lambda(x) (< 0 x))」という関数を渡しているため、リストの要素が0より大きい値があった時点でそれ以降のリストが返るようになているが、ここで、「(lambda(x) (<= 10 x))」とすると10以上の値があった時点での・・・というようにできる。

Rubyの場合
#!/usr/bin/ruby
# 第1引数:配列
# 第2引数:ブロック
def member_if ary, &proc
  return false if !ary # 配列がからだったらfalse
  return ary if proc.call(ary.first) # 関数を実行しtrueだったら配列を返す
  ary.shift # 配列の最初の要素を取り除く
  member_if(ary, &proc) # 再帰的にmember_ifを実行
end

# member_ifを実行し結果を出力
p member_if([-10,-5,-4,-3,0,10,20,30,40,50]) {|x|
  x > 0
}

と、Rubyでも似たようなことができるわけですね。(このコードがRuby的に綺麗かどうかはおいといて)
Javaでもできないかなー。次のJavaのバージョンでは実装されないみたい↓。残念。
Java7はしょぼくなりそう - yvsu pron. yas