6

私はJavaslang-2.1.0-alphaとそれに相当するJavaslang-matchを使用して、オブジェクトの分解を行っています。「マッチ・ザ・ファンシー・ウェイ」セクションのダニエルによるブログ投稿によるこれによると:

Match(person).of( Case(Person("Carl", Address($(), $())), (street, number) -> ...) )

and内の 2 つのワイルドカード パターンに一致する値を取得する必要がAddressありますが、この例はコンパイルさえしません。後で、すべてのオブジェクトをアトミック パターン内にラップする必要があることに気付きました。つまり、"Carl" は $("Carl") になります。これは、この問題を読んだ後でした。streetnumber

更新されたチュートリアルに従いましたが、この例には更新がありませんでした。

例を次のように更新しました。

Person person = new Person("Carl", new Address("Milkyway", 42));

 String result2 = Match(person).of(
 Case(Person($("Carl"), Address($(),$())),
         (street, number) -> "Carl lives in " + street + " " + number),
 Case($(), () -> "not found")
 );
 System.out.println(result2);

それはコンパイルされますが、コンソール出力から判断すると、私の値は適切に一致していません:

Carl lives in Carl Address [street=Milkyway, number=42]

Carlと、オブジェクト全体がstreet含まれていることは明らかです。numberAddress

Carlをキャッチするために 3 番目のラムダ パラメータを追加しようとすると、次のようになります。

 Case(Person($("Carl"), Address($(),$())),
         (name, street, number) -> "Carl lives in " + street + " " + number)

コードをコンパイルできません。ラムダ式に赤い下線が引かれ、次のエラー テキストが表示されます。

The target type of this expression must be a functional interface

$_最新バージョンの javaslang-match で値を無視する方法はありません。したがって、上記のように 3 つのラムダ パラメータを返すアトミック パターンのそれぞれに一致させたいと考えています。

このライブラリを理解し、最新バージョンでこのオブジェクト分解を行う方法を説明してくれる人が必要です。

4

1 に答える 1

8

免責事項:私は Javaslang の作成者です。

ケースは (String, Address) -> {...} を処理する必要があります。$() は任意の値に一致しますが、ハンドラー/関数は分解されたオブジェクト ツリーの最初のレイヤーのみを受け取ります。$() は2番目のレイヤーにあります。

ルール: すべてのレイヤーがパターンと照合され、最初のレイヤーのみがハンドラーに渡されます。

実際、Match の最初のプロトタイプは、任意のツリーの深さを処理しましたが、可能なすべての組み合わせに対して内部でメソッドを生成する必要がありました。最大バイトコードサイズを簡単に超え、コンパイル時間は指数関数的に無限に爆発しました。

現在のバージョンの Match は、現時点で私が目にする Java での唯一の実用的な方法です。

アップデート:

このトピックについて、より比喩的な最新情報を提供させてください。

私たちは区別します

  1. 入力のオブジェクトグラフ
  2. マッチケースに渡されたパターンツリー
  3. オブジェクト グラフの分解されたオブジェクト

広告 1) オブジェクトグラフ

オブジェクトを指定すると、オブジェクト グラフは、そのオブジェクトのプロパティ (それぞれのインスタンス変数) をトラバースすることによってスパンされます。特に、オブジェクトにサイクルが含まれることを禁止していません (たとえば、それ自体を含む変更可能なリスト)。

Javaslang では、オブジェクトをパーツに分解する自然な方法はありません。そのためには、いわゆるパターンが必要です。

オブジェクト グラフの例:

     Person        <-- root
      /   \
 "Carl"  Address   <-- 1st level
          /   \
 "Milkyway"    42  <-- 2nd level

広告 2) パターン ツリー

パターン (インスタンス) は、オブジェクトを分解する方法を本質的に定義します。

この例では、パターン タイプは次のようになります (簡略化されたジェネリック)。

 Pattern2<Person, String, Address<String, Integer>>
               /           \
 Pattern0<String>  Pattern2<Address, String, Integer>
                          /   \
          Pattern0<String>     Pattern0<Integer>

呼び出されたパターン メソッドは、上記の型のインスタンスを返します。

      Person(...)
        /    \
 $("Carl")  Address(...)
             /   \
           $()    $()

Javaslang の Match API は次のことを行います。

  1. personMatch インスタンスは、指定されたオブジェクトを最初の Case に渡します。
  2. ケースはpersonオブジェクトをパターンに渡しますPerson(...)
  3. このパターンは、指定されたオブジェクトがタイプであるPerson(...)かどうかをチェックします。 personPerson
    • true の場合、パターンはオブジェクトをパーツ (タプルで表される) に分解し、サブパターンがこれらのパーツ$("Carl")Address(...)一致するかどうかをチェックします (3. を再帰的に繰り返します)。
    • false の場合、Match はオブジェクトを次の Case に渡します (2 を参照)。
    • パターンがアトミックである場合、つまり、オブジェクトをこれ以上分解できない場合、等価性がチェックされ、呼び出し元は一致ケースまでずっと通知されます。
  4. マッチ ケースがパターン マッチを取得すると、オブジェクト グラフの最初のレベルの分解されたオブジェクトがマッチ ケース ハンドラに渡されます。

現在、Java の型システムでは、任意のオブジェクト グラフ/ツリー レベルの一致したオブジェクトを型付きの方法でハンドラーに渡すことはできません。

広告 3) 分解されたオブジェクト

オブジェクトの分解については、2) ですでに説明しました。特に、指定されたオブジェクトの一部がパターン ツリーに送信されるときに使用されます。

上記の型システムの制限により、オブジェクトを照合するプロセスと、分解された部分を処理するプロセスを分離します。

Java では、任意のオブジェクト グラフを照合できます。ここでは、どのレベルにも限定されません。

ただし、オブジェクトが正常に一致した場合、最初のレイヤーの分解されたオブジェクトのみをハンドラーに渡すことができます。

この例では、これらの分解されたオブジェクトはnameaddress指定されたperson( and ではなく) のstreetandnumberです。


これは、Match API のユーザーには明らかではありません。

次の Java バージョンの 1 つには、値オブジェクトとネイティブ パターン マッチングが含まれます。ただし、そのバージョンのパターン マッチングは完全に最初のレベルに限定されます。

Javaslang では、任意のオブジェクト グラフを照合できますが、代償があります。ハンドラーは、分解されたオブジェクトの最初のレイヤーのみを受け取るため、混乱する可能性があります。

これが理解できる方法で質問に答えたことを願っています。

- ダニエル

于 2017-01-11T11:53:32.730 に答える