Javaで継続渡し

id:carbuncle:20060317を見て面白そうだったので、Javaで継続渡しを書いてみた。

public interface Continuable
{
    public Object applyN(Continuable cont, Object[] args);
}
public class NullContinuation implements Continuable
{
    private static NullContinuation instance;

    public static NullContinuation getInstance()
    {
        if (instance == null) {
            instance = new NullContinuation();
        }
        return instance;
    }

    // This class cannot be instantiated from outer classes.
    private NullContinuation() {}

    public Object applyN(Continuable cont, Object[] args)
    {
        return args;
    }
}
public class Fibonacci implements Continuable
{
    public Object applyN(Continuable cont, Object[] args)
    {
        int n = (Integer) args[0];
        if ((n == 1) || (n == 2)) {
            return cont.applyN(NullContinuation.getInstance(),
                               new Object[] { 1 });
        } else {
            final Fibonacci fib = this;
            final Continuable _cont = cont;
            final int _n = n;
            return fib.applyN(new Continuable() {
                    public Object applyN(Continuable cont, Object[] args) {
                        final int v1 = (Integer) args[0];
                        return fib.applyN(new Continuable() {
                                public Object applyN(Continuable cont, Object[] args) {
                                    final int v2 = (Integer) args[0];
                                    return _cont.applyN(NullContinuation.getInstance(),
                                                        new Object[] { v1 + v2 });
                                }
                            }, new Object[] { _n - 2 });
                    }
                }, new Object[] { _n - 1 });
        }
    }

    public static void main(String[] args)
    {
        NullContinuation nullCont = NullContinuation.getInstance();
        Fibonacci fib = new Fibonacci();

        for (int n = 1; n < 10; n++) {
            Object[] fibN = (Object[]) fib.applyN(nullCont, new Object[] { n });
            System.out.println("Fibonacci(" + n + ") = " + (Integer) fibN[0]);
        }
    }
}

こんな感じかな。なんかNullContinuationの辺りが一部怪しい気もするけど。
いやーJavaで無名クラスをこんな風に使いまくるコードは初めて書いた(笑)。

  • 実行結果:
% java Fibonacci
Fibonacci(1) = 1
Fibonacci(2) = 1
Fibonacci(3) = 2
Fibonacci(4) = 3
Fibonacci(5) = 5
Fibonacci(6) = 8
Fibonacci(7) = 13
Fibonacci(8) = 21
Fibonacci(9) = 34

ちなみに、こんなコードをいきなり書けるわけはないので、以下のようなSchemeプログラムを書いて、それからJavaに変換した。

(define (fib n)
  (if (or (= n 1) (= n 2))
      1
      (+ (fib (- n 1))
         (fib (- n 2)))))
(define (fib_cps n k)
  (if (or (= n 1) (= n 2))
      (k 1)
      (fib_cps (- n 1)
               (lambda (v1)
                 (fib_cps (- n 2)
                          (lambda (v2)
                            (k (+ v1 v2))))))))

Schemeを知らない人にも、少しは分かってもらえたかな?(逆に分かりにくくなっているという噂も)