Javaslang 对象分解不起作用

Javaslang object decomposition not working

我正在使用 Javaslang-2.1.0-alpha 及其等效的 Javaslang-match 来进行一些对象分解。根据 Daniel 在 "Match the Fancy way" 部分的 this by blog post:

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

应该将匹配 Address 内的两个通配符模式的值检索到 streetnumber 中,但该示例甚至无法编译。后来我意识到所有对象都必须包含在原子模式中,即 "Carl" 变成 $("Carl")。这是在阅读 this issue.

之后

我遵循了 updated tutorial 但是这个例子没有更新。

我将示例更新为:

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]

显然street包含Carlnumber,整个Address对象。

当我尝试添加第三个 lambda 参数来捕获 Carl:

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

代码无法编译,lambda 表达式带有红色下划线,错误文本如下:

The target type of this expression must be a functional interface

在最新版本的 javaslang-match 中无法忽略带有 $_ 的值。所以我想匹配每个原子模式,如上所示 return 三个 lambda 参数。

我需要了解这个库的人向我解释如何在最新版本中进行这个对象分解。

免责声明:我是Java俚语的创造者。

案例需要处理 (String, Address) -> {...}。 $() 匹配任意值,但 handler/function 仅接收分解对象树的第一层。 $() 在第二层。

规则:所有层都与模式匹配,只有第一层传递给处理程序。

Match 的第一个原型实际上处理了任意树深度,但是在幕后为所有可能的组合生成了方法 - 很容易超过最大字节代码大小并且编译时间呈指数级增长到无限。

当前版本的 Match 是 Java 我目前看到的唯一实用方法。

更新:

请允许我就此主题进行更形象的更新。

我们区分

  1. 输入
  2. 对象图
  3. 模式树传递给匹配案例
  4. 对象图的分解对象

广告 1) 对象图

给定一个对象,通过遍历该对象的属性(resp. 实例变量)来生成对象图。值得注意的是,我们不禁止对象包含循环(例如,包含自身的可变列表)。

在Java俚语中没有自然如何将对象分解成多个部分的方法。为此,我们需要一个所谓的 模式

对象图示例:

     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>

以上类型的调用模式方法return个实例:

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

Java俚语匹配 API 执行以下操作:

  1. Match 实例将给定的 person 对象传递给第一个 Case。
  2. 案例将 person 对象传递给模式 Person(...)
  3. Person(...) 模式检查给定对象 person 是否属于 Person 类型。
    • 如果为真,则模式会将对象分解成多个部分 (由元组表示)并检查子模式 $("Carl")Address(...) 是否匹配这些部分(递归地重复 3.)
    • 如果为 false,则 Match 将对象传递给下一个 Case(见 2.)
    • 如果模式是原子的,即它不能再分解对象,则检查相等性并通知调用者一路返回到匹配情况。
  4. 当匹配案例获得模式匹配时然后它将对象图第一层的分解对象传递给匹配案例处理程序。

目前Java的类型系统不允许我们以类型化的方式将任意对象graph/tree级别的匹配对象传递给处理程序。

广告 3) 分解对象

我们已经在上面的2)中提到了对象分解。特别是当我们给定对象的一部分被发送到模式树时,它会被使用。

由于我们上面提到的类型系统的限制,我们将匹配对象的过程与处理的过程分开分解的部分。

Java 允许我们匹配任意对象图。我们这里不局限于任何级别。

但是,当对象匹配成功后,我们只能将第一层分解后的对象传递给handler

在我们的示例中,这些分解对象是给定 personnameaddress(而不是 streetnumber)。


我知道这对 Match 的用户来说并不明显 API。

下一个 Java 版本将包含值对象和本机模式匹配!但是,该版本的模式匹配将完全限于第一级。

Java俚语允许匹配任意对象图——但它有代价。处理程序只接收第一层分解对象,这可能会造成混淆。

我希望这能以一种易于理解的方式回答问题。

- 丹尼尔