Scala 3:类型化元组压缩

2024-02-01

我正在尝试将元组压缩在一起并使用匹配类型来获取生成的压缩的确切类型。我有一个匹配类型和功能:

  type Z[A <: Tuple, B <: Tuple] <: Tuple = (A, B) match
    case (EmptyTuple, EmptyTuple) => EmptyTuple
    case (a *: as, b *: bs) => (a, b) *: Z[as, bs]

  def z[A <: Tuple, B <: Tuple](a: A, b: B): Z[A, B] = (a, b) match
    case (EmptyTuple, EmptyTuple) => EmptyTuple
    case (ah *: at, bh *: bt) => (ah, bh) *: z(at, bt)

然而,这两种情况都在z()结果出现错误:Found: EmptyTuple.type Required: test.Tuples.Z[A, B] and Found: (Any, Any) *: test.Tuples.Z[Tuple, Tuple] Required: test.Tuples.Z[A, B], 分别。我本以为这将是匹配类型的一个非常简单的应用,但显然我错了。我在这里缺少什么?

我还想限制匹配类型和功能z()具有相同长度的元组(例如如何无形'Length可以在 scala 2) 中使用,但也许这是一个单独的问题。

EDIT:

我设法得到了这个功能z()使用显式转换,但我仍然认为必须有一种方法可以避免这种情况:

  def z[A <: Tuple, B <: Tuple, M <: Int](a: A, b: B): Z[A, B] = (a, b) match
    case (ah *: at, bh *: bt) => ((ah, bh) *: z(at, bt)).asInstanceOf[Z[A, B]]
    case (EmptyTuple, EmptyTuple) => EmptyTuple.asInstanceOf[Z[A, B]]

另外,我能够得到该函数的长度方面z()以及,但我很想知道是否有一个更清晰/更简洁的方法来实现这一点(也许不需要定义L) 和 b) 如果有办法将类型参数限制为Z是相同长度的元组:

  type L[T <: Tuple] <: Int = T match
    case EmptyTuple => 0
    case _ *: t => 1 + L[t]

  type Z[A <: Tuple, B <: Tuple] <: Tuple = (A, B) match
    case (EmptyTuple, EmptyTuple) => EmptyTuple
    case (a *: as, b *: bs) => (a, b) *: Z[as, bs]

  def z[A <: Tuple, B <: Tuple, M <: Int](a: A, b: B)(using L[A] =:= L[B]): Z[A, B] = (a, b) match
    case (ah *: at, bh *: bt) => ((ah, bh) *: z(at, bt)).asInstanceOf[Z[A, B]]
    case (EmptyTuple, EmptyTuple) => EmptyTuple.asInstanceOf[Z[A, B]]

  println(z(1 *: true *: EmptyTuple, "seven" *: 9.8 *: EmptyTuple)) // <-- correctly zips tuples: ((1,seven),(true,9.8))

//    println(z(1 *: EmptyTuple, "seven" *: 9.8 *: EmptyTuple)) // <-- results in compile-time error as desired: "Cannot prove that test.Tuples.L[(Int *: EmptyTuple.type)] =:= test.Tuples.L[(String, Double)]..."

编辑2: 所以实际上事实证明元组长度已经被限制为相等,否则匹配类型Z没有解决,所以我想问题只是如何避免强制转换z().


现在匹配类型 https://docs.scala-lang.org/scala3/reference/new-types/match-types.html价值水平有很多限制:

这种匹配表达式的特殊输入模式仅在以下情况下使用: 满足以下条件:

  1. 匹配表达式模式没有防护
  2. 匹配表达式受检者类型是匹配类型受检者类型的子类型
  3. 匹配表达式和匹配类型具有相同的事例数
  4. 匹配表达式模式都是类型化模式 https://scala-lang.org/files/archive/spec/2.13/08-pattern-matching.html#typed-patterns,这些类型是=:=到匹配类型中相应的类型模式

你的代码

type Z[A <: Tuple, B <: Tuple] <: Tuple = (A, B) match
  case (EmptyTuple, EmptyTuple) => EmptyTuple
  case (a *: as, b *: bs) => (a, b) *: Z[as, bs]

def z[A <: Tuple, B <: Tuple](a: A, b: B): Z[A, B] = (a, b) match
  case (EmptyTuple, EmptyTuple) => EmptyTuple
  case (ah *: at, bh *: bt) => (ah, bh) *: z(at, bt)

打破条件4。case (EmptyTuple, EmptyTuple) and case (ah *: at, bh *: bt)不是键入的模式。

尝试一下是有意义的

type Z[A <: Tuple, B <: Tuple] <: Tuple = (A, B) match
  case (EmptyTuple, EmptyTuple) => EmptyTuple
  case (a *: as, b *: bs) => (a, b) *: Z[as, bs]

def z[A <: Tuple, B <: Tuple](a: A, b: B): Z[A, B] = (a, b) match
  case _: (EmptyTuple, EmptyTuple) => EmptyTuple
  case t: (_ *: _, _ *: _) => t match
    case (ah *: at, bh *: bt) => (ah, bh) *: z(at, bt)

但不幸的是,由于类型擦除,这不起作用

z((1, "a"), (true, 2.0)) // ()

实际上,case _: (EmptyTuple, EmptyTuple) and case t: (_ *: _, _ *: _)只是case _: (_, _)并匹配一切。如果我们交换箱子z((1, "a"), (true, 2.0))抛出运行时异常(java.lang.IndexOutOfBoundsException: 0).

以下使用嵌套匹配类型/模式匹配的方法似乎有效

type Z[A <: Tuple, B <: Tuple] <: Tuple = A match
  case EmptyTuple => Z1[B]
  case a *: as => Z2[a, as, B]

type Z1[B <: Tuple] <: Tuple = B match
  case EmptyTuple => EmptyTuple

type Z2[A, As <: Tuple, B <: Tuple] <: Tuple = B match
  case b *: bs => (A, b) *: Z[As, bs]

def z[A <: Tuple, B <: Tuple](a: A, b: B): Z[A, B] = a match
  case _: EmptyTuple => z1(b)
  case a1: (_ *: _) => a1 match
    case a2 *: as => z2(a2, as, b)

def z1[B <: Tuple](b: B): Z1[B] = b match
  case _: EmptyTuple => EmptyTuple

def z2[A, As <: Tuple, B <: Tuple](a: A, as: As, b: B): Z2[A, As, B] = b match
  case b1: (_ *: _) => b1 match
    case b2 *: bs => (a, b2) *: z(as, bs)

// compiles
summon[Z[(Int, String), (Boolean, Double)] =:= ((Int, Boolean), (String, Double))]

z((1, "a"), (true, 2.0)) // ((1,true),(a,2.0))

//   doesn't compile
// summon[Z[(Int, String, Long), (Boolean, Double)] =:= ((Int, Boolean), (String, Double))]
// z((1, "a", 3L), (true, 2.0))
//   Match type reduction failed since selector EmptyTuple.type
//   matches none of the cases
//     case b *: bs => (Long, b) *: Z[EmptyTuple.type, bs]

//   doesn't compile
// summon[Z[(Int, String), (Boolean, Double, Long)] =:= ((Int, Boolean), (String, Double))]
// z((1, "a"), (true, 2.0, 3L))
//   Match type reduction failed since selector  Long *: EmptyTuple.type
//   matches none of the cases
//     case EmptyTuple => EmptyTuple 

如何让匹配类型在 Scala 3 中正常工作 https://stackoverflow.com/questions/64434175/how-to-get-match-type-to-work-correctly-in-scala-3

Shapeless3 和注释 https://stackoverflow.com/questions/74355212/shapeless3-and-annotations

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Scala 3:类型化元组压缩 的相关文章

随机推荐

  • 如何在 Android 应用程序中将图像上传到 FTP 服务器?

    是否可以将图像从我的 Android 应用程序上传到 FTP 服务器 该图像已经使用相机捕获 在桌面应用程序中 我们使用 FTP 客户端将任何文件 图像上传到实时服务器 我们如何在 Android 应用程序中做类似的事情 使用这个对我来说效
  • 在蓝牙打印机上打印

    我需要在蓝牙打印机上打印 我已经有一个用于 Windows 移动平台的程序 它通过蓝牙将命令和数据发送到斑马 RW 420 打印机 http www zebra com id zebra na en index products print
  • 如何使用 Spring 的 @Cacheable 和 Aerospike 作为缓存?

    我只想用Aerospike作为后备缓存Spring CacheManager 当我不打算使用时我应该使用 spring data aerospikeAerospike作为数据存储但仅作为缓存 有没有类似的实现HazelcastCacheMa
  • 使用 .NET Core(API 和 HTTP)创建 Azure AD 应用程序和服务主体

    继续我以编程方式创建 Azure 应用程序的探索 这从https stackoverflow com a 44753728 1332416 https stackoverflow com a 44753728 1332416 我的核心获得了
  • 所有 C# 转换都会导致装箱/拆箱吗

    我很想知道 C 中的所有强制转换是否都会导致装箱 如果不是 那么所有强制转换都是成 本高昂的操作吗 示例取自装箱和拆箱 C 编程指南 http msdn microsoft com en us library yz2be5wk aspx i
  • 可以从纯虚函数返回引用吗?

    class I public virtual std wstring const GetName const 0 通常 实现此接口的客户端将其名称包含在其主体中 一切都很好 但有时 GetName 的结果是在函数执行期间计算的 使用静态变量
  • Angular2 中使用 [attr.attributeName] 和 [attributeName] 绑定属性之间的区别

    我是 Angular2 的新手 当 iam 绑定属性时 我通常按以下方式进行操作 示例1
  • 如何以编程方式判断系统是 R/3 还是 S/4

    是否可以通过代码判断当前系统是R 3还是S 4 我需要它 因为我有一个返回人力资源相关数据的软件组件的方法 但这个组件应该与R 3和S 4系统不同 DATA lv software component mo configuration gt
  • 如何解决 ASP.NET Web API 中的连接超时过期问题?

    我使用 ASP NET Web API 从数据库中检索大量数据作为 json 数据列表 但在浏览器控制台中收到此错误 Failed to load resource the server responded with a status of
  • 以编程方式更改数据库连接

    在 Oracle SQL Developer 中 我需要手动切换活动数据库连接 假设登录凭据已保存 是否有一个命令可以以编程方式连接到不同的数据库 我试图避免单击窗口右上角的下拉菜单来选择活动连接 也许我应该宁愿每个数据库有一个 SQL 文
  • 使用PHPUnit测试cookie和session,如何?

    使用 PHPUnit 可以很容易地测试原始 PHP 代码 但是严重依赖 cookie 的代码又如何呢 会议可能是一个很好的例子 有没有不需要我设置的方法 COOKIE测试期间的数据 这感觉像是一种很古怪的做事方式 这是代码的常见问题 尤其是
  • 如何用Scrapy爬取整个网站?

    我无法抓取整个网站 Scrapy 只能抓取表面 我想抓取得更深 过去 5 6 个小时一直在谷歌搜索 但没有任何帮助 我的代码如下 from scrapy contrib spiders import CrawlSpider Rule fro
  • 如何从Struts1中的url中删除'.do'前缀?

    我在 Struts 1 框架中编写了一个 Web 应用程序 一切正常 但在表单提交时 当用户转发到显示的下一页 URL 时actionname do 我不希望 URL 上有这个 Struts 1 默认后缀 相反 我想在 URL 中看到页面的
  • 横向打印图像?

    我正在将控件转换为位图并打印它 using MemoryStream ms new MemoryStream chart1 SaveImage ms ChartImageFormat Bmp Bitmap bm new Bitmap ms
  • Django 无法加载模块“debug_toolbar”:没有名为“debug_toolbar”的模块

    当我尝试运行该项目时 Django 由于某种原因无法加载 django debug toolbar 插件 错误消息说 web 1 ModuleNotFoundError No module named debug toolbar 这是我的设
  • Eclipse RCP 应用程序自定义工具栏

    我正在为我的 RCP 应用程序创建一个自定义工具栏 如图所示 我想要一个带有其他三个文本框的下拉框 这些基本上都是输入框并且是相互依赖的 现在 每个盒子都属于不同的类 我想将它们集中在一个类中 以便更轻松地为彼此创建侦听器 protecte
  • 在Java中为链中的变量赋值[重复]

    这个问题在这里已经有答案了 可能的重复 Java 操作顺序 在一行中使用两个赋值运算符 https stackoverflow com questions 9440844 java order of operations using two
  • 空合并运算符 - 为什么要进行强制转换?

    谁能告诉我为什么以下语句中的第一个语句会引发编译错误而第二个语句不会 NewDatabase AddInParameter NewCommand SomeString DbType String SomeString DBNull Valu
  • 使用 Symfony 2 将数组保存在 SQL 数据库中,Doctrine?

    我正在做应用程序 我使用 SQL 并且我想将复选框值保存在一列中 我正在这样做 Assert NotBlank message please select Assert NotNull message please select Asser
  • Scala 3:类型化元组压缩

    我正在尝试将元组压缩在一起并使用匹配类型来获取生成的压缩的确切类型 我有一个匹配类型和功能 type Z A lt Tuple B lt Tuple lt Tuple A B match case EmptyTuple EmptyTuple