Java8でFunctionalJava

FunctionalJavaには、F1.javaやF2.javaなど、メソッド1つだけのabstract classを変更すればFunctionalInterfaceになるものが大量にあるので、ちょっと試してみました。
以下にわかりやすい書き換え例を上げておきます。
思ったよりも結構ラムダの型推論が効いて、(varが存在しない以外は) C# に匹敵するくらいまで、型を書かなくてよくなって素晴らしいですね。


一番顕著な例がこんな感じ
https://github.com/xuwei-k/functionaljava/commit/5372e395f923e16271cc131bdf8f13b837d741f9#L11R566
変換前↓(良くも悪くも頭おかしい)

public static <A, B, C, D, E, F$, G, H, I> F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>> curry(
      final F8<A, B, C, D, E, F$, G, H, I> f) {
    return new F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>>() {
      public F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>> f(final A a) {
        return new F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>() {
          public F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>> f(final B b) {
            return new F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>() {
              public F<D, F<E, F<F$, F<G, F<H, I>>>>> f(final C c) {
                return new F<D, F<E, F<F$, F<G, F<H, I>>>>>() {
                  public F<E, F<F$, F<G, F<H, I>>>> f(final D d) {
                    return new F<E, F<F$, F<G, F<H, I>>>>() {
                      public F<F$, F<G, F<H, I>>> f(final E e) {
                        return new F<F$, F<G, F<H, I>>>() {
                          public F<G, F<H, I>> f(final F$ f$) {
                            return new F<G, F<H, I>>() {
                              public F<H, I> f(final G g) {
                                return new F<H, I>() {
                                  public I f(final H h) {
                                    return f.f(a, b, c, d, e, f$, g, h);
                                  }
                                };
                              }
                            };
                          }
                        };
                      }
                    };
                  }
                };
              }
            };
          }
        };
      }
    };
  }

変換後↓

public static <A, B, C, D, E, F$, G, H, I> F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>> curry(
  final F8<A, B, C, D, E, F$, G, H, I> f) {
  return a -> b -> c -> d -> e -> f$ -> g -> h -> f.f(a, b, c, d, e, f$, g, h);
}

あとは、例えばこれ

public static <E> Parser<Stream<Character>, Digit, E> digit(final P1<E> missing, final F<Character, E> sat) {
  return StreamParser.satisfy(missing, sat, new F<Character, Boolean>() {
    public Boolean f(final Character c) {
      return Character.isDigit(c);
    }
  }).map(new F<Character, Digit>() {
    public Digit f(final Character c) {
      return Digit.fromChar(c).some();
    }
  });
}

が、以下のようになるわけですが

public static <E> Parser<Stream<Character>, Digit, E> digit(final P1<E> missing, final F<Character, E> sat) {
  return StreamParser.satisfy(missing, sat,
    c -> Character.isDigit(c)
  ).map(
    c -> Digit.fromChar(c).some()
  );
}


c -> Character.isDigit(c)という「単に引数をそのまま渡してメソッドを呼び出しているだけのパターン」は、以下のようにメソッド参照を使ってCharacter::isDigitというように、さらに簡略化できて、ラムダの引数に名前付けなくてすむのも地味に嬉しいですね

public static <E> Parser<Stream<Character>, Digit, E> digit(final P1<E> missing, final F<Character, E> sat) {
  return StreamParser.satisfy(missing, sat,
    Character::isDigit
  ).map(
    c -> Digit.fromChar(c).some()
  );
}

このあたりは、(微妙に文法が違うだけで) ScalaC# とおなじです。




他にもFunctionalJavaではSAM*1 type が使われているところがとても大量にあるので、まだまだ全部は変換できていませんが、途中のものを公開しておきます。


https://github.com/xuwei-k/functionaljava/commit/5372e395f92


ところで、sbtがJava8に全く対応してなくてmavenでビルドするのつらいです・・・(´・ω・`)はやく対応しないかな・・・。あと、maven詳しくなくて、調べるの面倒だったのでビルドファイルがcoreしか書き換えてなくてかなり雑なのですが、誰か・・・

*1:single abstract method