Java.use(better);
《目的》
関数型プログラミングを Java で実践するには、クロージャーに代わる仕掛が必要です。また、コレクション操作に欠かせない、UML2/OCL に準拠するメソッド群を実現する手法を紹介します。
《動機》
Java を導入したときに悩ましいのは、クロージャーが使えないことでした。遅々として進まない Java の状況に業を煮やして、Jython を導入した(2003年)のもそのためです。また、関数型プログラミングは、プログラミング言語の制約を受けないので、Java でも実践できます。それを経験しておくと、Scala など、関数型プログラミングの機能を備えた言語の理解にも役立ちます。
■ Java の隘路
コレクションを扱うときの問題点を探るために、数列を事例に話を進めます。以下は、数列を列挙するメソッド range が存在するものとして、次のように、
System.out.println(range(9)); ... [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0 から 9 までの数列が得られます。
□ 事例:collect 操作
数列の各要素を10倍にした、新たな数列が欲しいときには、
Listcase_collect1() { List seq = new Vector (); for (int e: range(9)) seq.add(e*10); return seq; } ... [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
各要素を追加するときに、式 e*10 を指定します。また、数列の各要素に10を加えた、新たな数列が欲しいときには、
Listcase_collect2() { List seq = new Vector (); for (int e: range(9)) seq.add(e+10); return seq; } ... [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
各要素を追加するときに、式 e+10 を指定します。
これらの違いは * と + だけです。ところが、残りのコードの断片は、繰り返し記述するしかありません。というのも、メソッド呼び出しの実引数に (e*10) や (e+10) を指定したくても、変数 e は、メソッドの本体でのみ有効です。なにか術はないでしょうか。
同様のことを Scala で実現すると、次のようになります。
scala> print( 0 to 9 ) Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) scala> print( 0 to 9 map { _*10 } ) Vector(0, 10, 20, 30, 40, 50, 60, 70, 80, 90)
メソッド map の引数に指定した式 _*10 は任意です。この変数 _ は、数列 0 to 9 の要素を順に参照します。そのため、残りのコードの断片は、他の目的にも再利用できます。また、Jython では、次のようになります。
>>> [e for e in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [e*10 for e in range(10)]
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
[ に続く式 e*10 は任意です。この変数 e は、数列 range(10) の要素を順に参照します。そのため、残りのコードの断片は、他の目的にも再利用できます。
□ 事例:select 操作
数列の中から偶数だけを選びたいときには、
static Listcase_select1() { List seq = new Vector (); for (int e: range(9)) if (e%2 == 0) seq.add(e); return seq; } ... [0, 2, 4, 6, 8]
各要素を追加するときに、式 e%2==0 を指定します。また、奇数だけを選びたいときには、
static Listcase_select2() { List seq = new Vector (); for (int e: range(9)) if (e%2 != 0) seq.add(e); return seq; } ... [1, 3, 5, 7, 9]
各要素を追加するときに、式 e%2!=0 を指定します。
これらの違いは = と ! だけです。ところが、残りのコードの断片は、繰り返し記述するしかありません。というのも、メソッド呼び出しの実引数に (e%2==0) や (e%2!=0) を指定したくても、変数 e は、メソッドの本体でのみ有効です。なにか術はないでしょうか。
同様のことを Scala で実現すると、次のようになります。
scala> print( 0 to 9 ) Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) scala> print( 0 to 9 filter { _%2 == 0 } ) Vector(0, 2, 4, 6, 8)
メソッド filter の引数に指定した条件式 _%2==0 は任意です。この変数 _ は、数列 0 to 9 の要素を順に参照します。そのため、残りのコードの断片は、他の目的にも再利用できます。また、Jython では、次のようになります。
>>> [e for e in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [e for e in range(10) if e%2 == 0]
[0, 2, 4, 6, 8]
if に続く条件式 e%2==0 は任意です。この変数 e は、数列 range(10) の要素を順に参照します。そのため、残りのコードの断片は、他の目的にも再利用できます。
↑ TOP
》作業中です《♪ 早乙女(さおとめ)