加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Scala – 无形的HList到TupleN,其中元组形状不需要与HList形状完

发布时间:2020-12-16 09:15:41 所属栏目:安全 来源:网络整理
导读:我想创建相当于: def toTupleN[A1,...,AN,L : HList](l: L): TupleN[A1,AN] 使用toTupleN的代码只有在l中恰好有一个N组合的值才能编译,可以创建元组.任何其他应该会产生编译时错误.应考虑可用的隐式转换.请注意,l的大小或其中的值的排序没有限制. 例: val
我想创建相当于:

def toTupleN[A1,...,AN,L <: HList](l: L): TupleN[A1,AN]

使用toTupleN的代码只有在l中恰好有一个N组合的值才能编译,可以创建元组.任何其他应该会产生编译时错误.应考虑可用的隐式转换.请注意,l的大小或其中的值的排序没有限制.

例:

val l = 23 :: (1,"wibble") :: (2,"wobble") :: "foo" :: HNil
// l: shapeless.::[Int,shapeless.::[(Int,String),shapeless.::[String,shapeless.HNil]]]] = 23 :: (1,wibble) :: (2,wobble) :: foo :: HNil

val t2: (String,Int) = toTuple2(l)
// t2: (String,Int) = (foo,23)

val nope: (String,String) = toTuple2(l)
// Compiler error because no combination of l's values can create nope

val nein: ((Int,String)) = toTuple2(l)
// Another compiler error because there is more than one way l's values can create nein

这个问题从answer到question出现.这个问题中更通用的机器可以使用FunctionN#tupled来创建数据结构并调用任何标准函数(其参数是不同类型的).

更新:

使用子类型定义所需行为的一些示例:

trait A
trait B extends A
trait C extends A

val a: A
val b: B
val c: C

toTuple2[(A,Int)](5 :: b :: HNil)      // (b,5): subtypes match supertypes when there is no exact match
toTuple2[(A,Int)](5 :: b :: a :: HNil) // (a,5): only one exact match is available
toTuple2[(A,Int)](5 :: a :: a :: HNil) // compile error: more than one exact match is available
toTuple2[(A,Int)](5 :: b :: c :: HNil) // compile error: more than one inexact match is available

解决方法

我无法使目标类型的推理工作完全按照你想要的方式工作,但是作为补偿,我通过无形的泛型推广到任意的产品类型,

import shapeless._,ops.hlist._,test._

object Demo {
  trait UniqueSelect[L <: HList,M <: HList] {
    def apply(l: L): M
  }

  object UniqueSelect {
    implicit def hnil[L <: HList]: UniqueSelect[L,HNil] =
      new UniqueSelect[L,HNil] {
        def apply(l: L): HNil = HNil
      }

    implicit def hcons[L <: HList,H,T <: HList,S <: HList]
      (implicit
        pt: Partition.Aux[L,H :: HNil,S],ust: UniqueSelect[S,T]
      ): UniqueSelect[L,H :: T] =
      new UniqueSelect[L,H :: T] {
        def apply(l: L): H :: T = {
          val (h :: HNil,s) = pt(l)
          h :: ust(s)
        }
      }
  }

  def toProductUniquely[P <: Product] = new ToProductUniquely[P]
  class ToProductUniquely[P <: Product] {
    def apply[L <: HList,M <: HList](l: L)
      (implicit gen: Generic.Aux[P,M],up: UniqueSelect[L,M]): P =
        gen.from(up(l))
  }

  val l = 23 :: (1,"wobble") :: "foo" :: HNil

  val t2 = toProductUniquely[(String,Int)](l)
  typed[(String,Int)](t2)
  assert(t2 == ("foo",23))

  illTyped("""
  toProductUniquely[(String,String)](l)
  """)

  illTyped("""
  toProductUniquely[Tuple1[(Int,String)]](l)
  """)
}

更新1

如果我们说我们有类型A和B<:A,那么对于所请求类型的子类型来满足选择的支持是非常简单的,则A :: B :: HNil中的A的选择是不明确的,因为两个元素都符合到A.这可以通过在以前的hcons定义中的证人添加一个SubtypeUnifier来完成,

import shapeless._,test._

object Demo extends App {
  trait UniqueSelect[L <: HList,M <: HList,S <: HList]
      (implicit
        su: SubtypeUnifier.Aux[L,pt: Partition.Aux[M,upt: UniqueSelect[S,s) = pt(su(l))
          h :: upt(s)
        }
      }
  }

  def toProductUniquely[P <: Product] = new ToProductUniquely[P]
  class ToProductUniquely[P <: Product] {
    def apply[L <: HList,M]): P =
        gen.from(up(l))
  }

  class A
  class B extends A
  class C

  val ac = new A :: new C :: HNil
  val bc = new B :: new C :: HNil
  val abc = new A :: new B :: new C :: HNil

  // Exact match
  val tac = toProductUniquely[(A,C)](ac)
  typed[(A,C)](tac)

  // Subtype
  val tbc = toProductUniquely[(A,C)](bc)
  typed[(A,C)](tbc)

  // Exact match again
  val tabc = toProductUniquely[(B,C)](abc)
  typed[(B,C)](tabc)

  // Ambiguous due to both elements conforming to A
  illTyped("""
  toProductUniquely[(A,C)](abc)
  """)
}

更新2

我们还可以适应一个统一的语义,它会优先于完全匹配,然后回到一个唯一的子类型,如更新的问题所述.我们通过组合上述两个解决方案的实例来实现:来自正常优先级的第一个实例的精确匹配实例和低优先级的子类型匹配实例,

import shapeless._,M <: HList] {
    def apply(l: L): M
  }

  object UniqueSelect extends UniqueSelect0 {
    implicit def hnil[L <: HList]: UniqueSelect[L,HNil] {
        def apply(l: L): HNil = HNil
      }

    implicit def hconsExact[L <: HList,s) = pt(l)
          h :: upt(s)
        }
      }
  }

  trait UniqueSelect0 {
    implicit def hconsSubtype[L <: HList,M]): P = gen.from(up(l))
  }

  trait A
  trait B extends A
  trait C extends A

  val a: A = new A {}
  val b: B = new B {}
  val c: C = new C {}

  // (b,5): subtypes match supertypes when there is no exact match
  toProductUniquely[(A,Int)](5 :: b :: HNil)

  // (a,5): only one exact match is available
  toProductUniquely[(A,Int)](5 :: b :: a :: HNil)

  // compile error: more than one exact match is available
  illTyped("""
  toProductUniquely[(A,Int)](5 :: a :: a :: HNil)
  """)

  // compile error: more than one inexact match is available
  illTyped("""
  toProductUniquely[(A,Int)](5 :: b :: c :: HNil)
  """)
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读