SICP : Ex2.06 : Java
[id:lethevert:20060113:p1]
チャーチ数を表現する問題。
クラスという余計な装飾がついたせいで、意味的には分かりにくくなってしまったかも。動作やできることはScheme版やConcurrent Clean版と同じ。
手続きを抽象化して、抽象化した手続きに対する手続き(つまり高階関数)を書くというテクニックは、関数型言語で非常に有用なプログラミングテクニックだが、Javaでも同じことができるということだ。
ちなみに、テストコードには、加算を使ったケースと、リスト操作を使ったケースの2種類を記述しておいた。
import java.util.*; abstract class F<X> { abstract X $(X x); //Haskell-like ;p } abstract class Church<X> { abstract X eval(F<X> f, X x); /* Some Calculations */ Church<X> add_1() { final Church<X> m = this; return new Church<X>() { X eval(F<X> f, X x) { return f.$(m.eval(f,x));}}; } Church<X> add(final Church<X> n) { final Church<X> m = this; return new Church<X>() { X eval(F<X> f, X x) { return m.eval(f, n.eval(f, x));}}; } Church<X> mult(final Church<X> n) { final Church<X> m = this; return new Church<X>() { X eval(final F<X> f, X x) { F<X> mf = new F<X>() { X $(X x) { return m.eval(f, x);}}; return n.eval(mf, x); } }; } } class Zero<X> extends Church<X> { X eval(F<X> f, X x) { return x;} } public class Main { public static void main(String[] args) { //Simple Integer Church<Integer> zero = new Zero<Integer>(); Church<Integer> three = zero.add_1().add_1().add_1(); Church<Integer> five = three.add_1().add_1(); F<Integer> f = new F<Integer>() { Integer $(Integer x) { return x+1;}}; System.out.println(zero.eval(f,0)); System.out.println(three.eval(f,0)); System.out.println(five.eval(f,0)); System.out.println(three.add(five).eval(f,0)); System.out.println(three.mult(five).eval(f,0)); //List Church<List> zeroL = new Zero<List>(); Church<List> threeL = zeroL.add_1().add_1().add_1(); Church<List> fiveL = threeL.add_1().add_1(); F<List> fL = new F<List>() { List $(List x) { x.add(1); return x;}}; System.out.println(zeroL.eval(fL,new LinkedList()).size()); System.out.println(threeL.eval(fL,new LinkedList()).size()); System.out.println(fiveL.eval(fL,new LinkedList()).size()); System.out.println(threeL.add(fiveL).eval(fL,new LinkedList()).size()); System.out.println(threeL.mult(fiveL).eval(fL,new LinkedList()).size()); } }