Javaの多項関数



思い出させてください:アリティは関数パラメーターの数です。 したがって、多項(この単語は一緒にまたは個別に記述できます)関数は、いくつかのパラメーターを持つ関数です。 Java 8では、1つと2つの入力パラメーターを持つ関数が導入されました。 しかし、さらにパラメーターがある場合はどうでしょうか?



多くの入力パラメーターが必要な場合



Javaには、Function <X、R>およびBiFunction <X、Y、R>があります。XおよびYは入力パラメーターのタイプで、Rは出力パラメーターのタイプです。 ただし、3つ以上の入力パラメーターを持つ関数は、自分で決定する必要があります。

そのような不正はどこから来るのでしょうか? クラス内の任意の数のパラメーターでメソッドを定義でき、3つ以上のパラメーターを持つ関数を具体的に定義する必要があるのはなぜですか?

しかし、必要に応じて、決定を試みます。 しかし、どのように? 確かに、カリー化について聞いたことがあります-N個のパラメーターを持つ関数をN-1個のパラメーターを持つ関数に変換する方法です。 そしておそらくこれは、多くの人々がすぐに考える最初のことです:私はマルチパラメーター(マルチパラメーター)関数をカリー化する必要があります! しかし、ここで特定の関数を変換する方法はありますか?

たとえば、次の関数があります





gxy=sinx+cosxy+minxy







あなたはすでにそれを思い浮かべる方法を推測しています





gxy=f2f1xy





それとも難しいですか? どうやって、この同じカレーですか? 最近、このテーマに関する記事に出くわしたようです...

私はあなたをこれ以上苦しませません。 心配しないでください。 Java 8がそれを行います。 たとえば、3つの入力パラメーターを使用して関数をさらに定義するには:





r=fabc





最初にインターフェースを一度定義する必要があります:

@FunctionalInterface public interface Function3Arity<A, B, C, R> { R apply(A a, B b, C c); }
      
      





その後、特定の種類の3項(3項)関数を定義できます。 たとえば、次のように:

 private static Function3Arity<Integer, String, Integer, String> f3 = (a, op, b) ->{return "" + a + op + b + "=" + (a+b);};
      
      





仕組みを確認してください。

 @Test public void testFunction3Arity() { String result = f3.apply(2, "+", 3); assertEquals("2+3=5", result); }
      
      





使用するアリティごとに適切なインターフェイスを定義する必要がありますN = 3.4、...

そして、すべてが良いでしょうが、唯一の悪いことは、合理的な方法でこの決定に到達することが単に不可能であることです。 (あなたが、私のように、関数型プログラミングの分野の専門家でない場合)。 つまり、applyメソッドが任意の数のパラメーターを認識して正しく解釈する能力を意味します。 これはドキュメントには書かれていません。 そして、これが他の方法でできるかどうかは書かれていません。 そして、このタスクに直面したとき、Functionクラスまたはそれを含むパッケージの仕様で類似したものを見つけたいと思っていました。 たとえば、 hereまたはhereです。



大量の出力パラメーターが必要な場合



多くの入力パラメーターが存在する例を見てみました。 しかし、出力パラメーターがたくさんある場合はどうでしょうか?

ご存じのとおり、Javaではreturnでプリミティブな要素またはオブジェクトを1つだけ返すことができます。 しかし、すでに関数シグネチャのレベルで入力パラメーターと出力パラメーターを区別できるようにしたいと思います。 すなわち 次のような署名があります。





cd=fab





残念ながら、これを直接行うことはできません。 出力パラメーターは何らかの形で構成する必要があります。 これを行うには、一時オブジェクトを作成するか、リストにパラメーターを書き込みます(リスト<?>)。 最初の方法は重く、2番目の方法は、出力パラメーターのタイプの静的制御が失われるため、これらのタイプが異なる場合は不快です。

私の観点からは、<TupleN <X1、X2、..Xn>の使用はよりエレガントです。

たとえば、Tuple2クラスは次のようになります。

 public class Tuple2<A, B> { public final A a1; public final B a2; public Tuple2(A t, B u) { a1 = Objects.requireNonNull(t); a2 = Objects.requireNonNull(u); } @Override public boolean equals(Object o) {…} @Override public int hashCode() {…} }
      
      





このクラスを使用すると、3つの入力パラメーターと2つの出力パラメーターを持つ関数を次のように定義できます。

 private static Function3Arity<Integer, String, Integer, Tuple2<Integer, String>> f3And2 = (a, op, b) ->{ int intValue = a + b; String sValue = "" + a + op + b + "=" + (a+b); return new Tuple2<>(intValue, sValue); };
      
      





仕組みを確認しましょう。

 @Test public void testFunction3And2Arity() { Tuple2<?,?> result = f3And2.apply(2, "+", 3); assertEquals(5, result.a1); assertEquals("2+3=5", result.a2); }
      
      





最終ルール



  1. 関数に3つ以上の入力パラメーターがある場合、新しいN-aryインターフェイスを定義し、それを使用して特定の関数を後で定義する必要があります。
  2. 関数に2つ以上の出力パラメーターがある場合、returnを使用して関数から出力する前にTupleNクラスを定義し、パラメーターをパックします。


私のGitHubプロジェクトコード例を見つけることができます。

イラスト: ゲラルト



All Articles