代码之家  ›  专栏  ›  技术社区  ›  Readren

如何定义标量。标量3中元组的ValueOf?

  •  1
  • Readren  · 技术社区  · 1 年前

    这个 ValueOf type函数可以在方法的上下文参数列表中用于选择singleton类型的单个居民,如果类型参数不是singleton,则会引发编译错误。

    enum Color { case red, green, blue }
    def singleInhabitantOf[T](using  holder: ValueOf[T]): T = holder.value
    println(singleInhabitantOf[Color.red.type] == Color.red) // outputs true
    

    但它是有限的。它不适用于组件类型都是singleton的元组。

    singleInhabitantOf[(Color.red.type, Color.blue.type)] // compile error
    

    错误消息为: 没有可用的单一值(Color.red、Color.blue);符合条件的单例类型 的值 综合包括文本和稳定路径。

    所以我试着用这种方式为元组创建一个版本:

    import scala.Tuple
    
    type ValuesOf[T <: Tuple] <: Tuple = T match {
        case EmptyTuple => EmptyTuple
        case h *: t => ValueOf[h] *: ValuesOf[t]
    }
    
    def singleInhabitantsOf[T<:Tuple](using holder: ValuesOf[T]): Tuple = holder // a tuple mapping is missing here but how to implement it is another question.
    
    singleInhabitantsOf[(Color.red.type, Color.blue.type)] // Copile error
    

    不幸的是,编译器抱怨说: 找不到参数持有者的ValuesOf[(Color.red,Color.blue)]类型的给定实例 . 显然,它在隐式上下文中寻找元组实例,而不是将元组与singletons实例合成。

    然而

    implicitly[summonAll[ValuesOf[T]]]
    

    编译和运行良好。 所以我可以使用重写方法 summonAll 这样地

    inline def singleInhabitantsOf2[T <: Tuple]: Tuple = summonAll[ValuesOf[T]] 
    

    但这个解决方案对我的最终目的没有用处,因为单重性的检查应该在方法签名中,这样,如果出现问题,编译器就不会开始处理主体。

    关于如何定义在上下文参数列表中使用元组的ValueOf,有什么想法吗?

    1 回复  |  直到 1 年前
        1
  •  3
  •   Dmytro Mitin    1 年前

    类型类和匹配类型是Scala3中执行类型级计算的两种方法(如Scala2中的类型投影和类型类,Haskell中的类型族和类型类)。

    混合类型类和匹配类型可能很棘手。

    你似乎想要类型类而不是匹配类型

    trait ValuesOf[T <: Tuple]:
      def value: T
    
    object ValuesOf:
      given ValuesOf[EmptyTuple] with
        val value = EmptyTuple
    
      given [h, t <: Tuple](using vh: ValueOf[h], vt: ValuesOf[t]): ValuesOf[h *: t] with
        val value = vh.value *: vt.value
    
    def singleInhabitantsOf[T <: Tuple](using holder: ValuesOf[T]): T = holder.value
    
    singleInhabitantsOf[(Color.red.type, Color.blue.type)] // (red,blue)
    

    但这个解决方案对我的最终目的没有用处,因为单重性的检查应该在方法签名中,这样,如果出现问题,编译器就不会开始处理主体。

    听起来有点奇怪。您可以始终从左侧到右侧“隐藏”隐式参数。在Scala 2中,您可以重写

    def foo[A](implicit tc: TC[A]): Unit = ()
    

    def foo[A]: Unit = macro fooImpl[A]
    
    def fooImpl[A: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
      import c.universe._
      c.inferImplicitValue(weakTypeOf[TC[A]])
      q"()"
    }
    

    在Scala 3中,您可以重写

    def foo[A](using TC[A]): Unit = ()
    

    inline def foo[A]: Unit =
      summonInline[TC[A]]
      ()
    

    也许你可以告诉更多关于你的实际问题(也许开始一个新问题),我们可以看看它是否可以通过匹配类型来解决, summonAll , constValueTuple 和其他来自 scala.compiletime.* .

    推荐文章