このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

Javaで高階プログラミング、ってそれ何よ!

昨日の「プログラマのための述語論理」で、暗黙的に“総称的な高階関数”が出現してしまいました。それで今日は、意図的に「Java高階関数を扱えるだろうか? 」とやってみました。結論を先に言えば、ちょっとシンドい

関数オブジェクト

まずは、関数オブジェクトを次のインターフェースで定義します。


public interface Function<X, Y> {
Y apply(X x);
}

Function<X, Y>をimplementsするクラスのインスタンスは、型がX→Yの関数です(そう思いこむことにする)。f(x) の代わりに f.apply(x) と書く必要がありますが、我慢しましょう。

2引数関数はというと、次のインターフェースを使う手があります。


public interface FunctionOfArity2<X1, X2, Y> {
Y apply(X1 x1, X2 x2);
}

が、今回はペア(長さ2のタプル)を使いましょう。


public class Pair<X1, X2> {
private X1 _1;
private X2 _2;
public Pair(X1 x1, X2 x2) {
_1 = x1;
_2 = x2;
}
public X1 first() {return _1;}
public X2 second() {return _2;}
}

(X1, X2→Y)という型の関数は、Function<Pair<X1, X2>, Y>型だとみなします。

実例:足し算関数

毎度お馴染みの足し算する関数を定義して実行してみます。


public class Sum {
public static void main(String[] args) {
Function<Pair<Integer, Integer>, Integer> sum =
new Function<Pair<Integer, Integer>, Integer>() {
public Integer apply(Pair<Integer, Integer> arg) {
return arg.first() + arg.second(); // ここが本体
}
};
// y = 5 + 3;
int y = sum.apply(new Pair<Integer, Integer>(5, 3));
System.out.println("y = " + y);
}
}


C:\tmp>java Sum
y = 8

それでカリー化

これまたお決まりのカリー化、いってみよう。(JavaScriptのカリー化、「ハラワタを取り出して改変してからもう一度突っこむ」というブラックジャック式にえぐい/ださい方法が→http://d.hatena.ne.jp/m-hiyama/20051213/1134446855にあります。)


public class Curry<X, Y, Z> implements
Function<Function<Pair<X, Y>, Z>, Function<X, Function<Y, Z>>>
{
public Function<X, Function<Y, Z>>
apply(final Function<Pair<X, Y>, Z> func)
{
return new Function<X, Function<Y, Z>>() {
public Function<Y, Z> apply(final X x) {
return new Function<Y, Z>() {
public Z apply(Y y) {
return func.apply(new Pair<X, Y>(x, y));
}
};
}
};
}
}

ウニョニョ、なんじゃこりゃー。ほんとにカリー化になっているの?


public class CurrySample {
public static void main(String[] args) {
// 最初の例
// curry(sum)(5)(3) = 8
Function<Pair<Integer, Integer>, Integer> sum =
new Function<Pair<Integer, Integer>, Integer>() {
public Integer apply(Pair<Integer, Integer> arg) {
return arg.first() + arg.second();
}
};

Curry<Integer, Integer, Integer> int_int_int_curry =
new Curry<Integer, Integer, Integer>();
Function<Integer, Integer> sum5 =
(int_int_int_curry.apply(sum)).apply(5);
int y = sum5.apply(3);
System.out.println("y = " + y); // y = 5 + 3 = 8

// もうひとつの例
// curry(repeat)("Hi")(4) = "HiHiHiHi"
Function<Pair<String, Integer>, String> repeat =
new Function<Pair<String, Integer>, String>() {
public String apply(Pair<String, Integer> arg) {
String s = "";
String x = arg.first();
for (int i = 0; i < arg.second(); i++) {
s = s + x;
}
return s;
}
};

Curry<String, Integer, String> str_int_str_curry =
new Curry<String, Integer, String>();
Function<Integer, String> repeatHi =
(str_int_str_curry.apply(repeat)).apply("Hi");
System.out.println(repeatHi.apply(4)); // HiHiHiHi
}
}


C:\tmp>java CurrySample
y = 8
HiHiHiHi

なっ、なってるみたいです。

それがどうした

別にどうもしません。やってみただけ。特にお勧めはしません。