Scala 3 类型绑定 `<:<` 元组技巧

Posted

技术标签:

【中文标题】Scala 3 类型绑定 `<:<` 元组技巧【英文标题】:Scala 3 type bound `<:<` trick for tuples 【发布时间】:2021-04-18 12:25:18 【问题描述】:

在线会议期间,Adam Warski 展示了一个技巧来证明元组具有一定的结构:

第一个实现是

    def sequence[T <: Tuple](t: T): Option[InverseMap[T, Option]] =
        val unwrapped = t.productIterator.collect  case Some(v) => v.toArray[Any]
        if unwrapped.length == t.productArity then Some(Tuple.fromArray(unwrapped).asInstanceOf[InverseMap[T, Option]])
        else None

允许(但不应该)

sequence(("x", true)) // compiles

还有一个技巧来实现

def betterSequence[T <: Tuple](t: T)(using T <:< Map[InverseMap[T, Option], Option]): Option[InverseMap[T, Option]] =
    val unwrapped = t.productIterator.collect  case Some(v) => v.toArray[Any]
    if unwrapped.length == t.productArity then Some(Tuple.fromArray(unwrapped).asInstanceOf[InverseMap[T, Option]])
    else None
betterSequence(("x", true)) // compile error

能不能解释一下

(using T <:< Map[InverseMap[T, Option], Option])

有效,为什么TMap 的子类型?

【问题讨论】:

【参考方案1】:

InverseMap[T, Foo] 接受一个看起来像(Foo[t1], Foo[t2], ..., Foo[tn]) 的元组T 并将其转换为一个元组(t1, t2, ..., tn)。如果T 没有该结构,即它不是一堆Foos,它将无法编译(带有一些神秘的错误)。这是证明元组中只有Options 的主要内容。

下一个问题是如何将这种类型插入到betterSequence 方法中。 Map[T, Foo] 将看起来像 (t1, t2, ..., tn) 的元组 T 转换为 (Foo[t1], Foo[t2], ..., Foo[tn])InverseMap 的倒数)。因此,Map[InverseMap[T, Option], Option] 只是 T(想想数学,其中 f(f^-1(x)) 又是 x。绑定的 T &lt;:&lt; T 将始终为真,但前提是 InverseMap 首先成功。

【讨论】:

没错,没有注意到我们有 f(f^-1(x)) 的情况。谢谢!

以上是关于Scala 3 类型绑定 `<:<` 元组技巧的主要内容,如果未能解决你的问题,请参考以下文章

scala - 高阶函数将类型T更改为Nothing

Scala泛型[T]的使用

Scala 宏介绍

Scala的泛型

Scala的类与类型

Scala学习笔记-表达式归纳