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

scala – 将无形HList转换为较小的HList

发布时间:2020-12-16 19:09:51 所属栏目:安全 来源:网络整理
导读:我有一个无形的HList,具有以下结构: type ABCAB = List[A] :: List[B] :: List[C] :: List[A] :: List[B] :: HNilval abcab: ABCAB = List[A]() :: List(B) :: List[C]() :: List(A) :: List(B) :: HNil 我想转换成一个更简单的类型,其中从左到右追加相同类
我有一个无形的HList,具有以下结构:

type ABCAB = List[A] :: List[B] :: List[C] :: List[A] :: List[B] :: HNil
val abcab: ABCAB = List[A]() :: List(B) :: List[C]() :: List(A) :: List(B) :: HNil

我想转换成一个更简单的类型,其中从左到右追加相同类型的列表:

type ABC = List[A] :: List[B] :: List[C] :: HNil        
val abc: ABC = abcab.magic                       // does magic exist in shapeless?
abc == List(A) :: List(B,B) :: List[C]() :: HNil // true

为什么在无形v1.2.4中有一些内置功能吗?

解决方法

虽然在另一个答案(引入一个新的类型)中采用的方法将起作用,但是可以使用更通用的机器来解决这个问题 – 并且与在价值水平上解决类似问题的方式没有什么不同.

我们将使用左折.编写组合函数有点棘手,因为我们有两种情况(我们已经看到一个与当前元素具有相同类型的元素,或者我们没有),我们必须使用隐式优先级技巧来避免模糊隐含值:

import shapeless._

trait LowPriorityCombine extends Poly2 {
  implicit def notAlreadySeen[L <: HList,A](implicit
    p: Prepend[L,List[A] :: HNil]
  ) = at[L,List[A]](_ :+ _)
}

object combine extends LowPriorityCombine {
  implicit def alreadySeen[L <: HList,A](implicit
    s: Selector[L,List[A]],r: Replacer[L,List[A],List[A]]
  ) = at[L,List[A]] {
    case (acc,as) => acc.updatedElem[List[A]](acc.select[List[A]] ++ as)
  }
}

但后来我们基本上完成了:

def magic[L <: HList](l: L)(implicit f: LeftFolder[L,HNil.type,combine.type]) =
  l.foldLeft(HNil)(combine)

我们可以证明它有效:

val xs = List(1,2,3) :: List('a,'b) :: List("X","Y") :: List(4,5) :: HNil
val test = magic(xs)

然后:

scala> test == List(1,3,4,5) :: List('a,"Y") :: HNil
res0: Boolean = true

正如所料.

上面的代码是针对1.2.4编写的,但它应该在2.0上进行一些非常小的修改.

更新:记录,这是2.0的工作版本:

import shapeless._,ops.hlist.{ LeftFolder,Prepend,Replacer,Selector }

trait LowPriorityCombine extends Poly2 {
  implicit def notAlreadySeen[L <: HList,A,Out <: HList](implicit
    p: Prepend.Aux[L,List[A] :: HNil,Out]
  ): Case.Aux[L,Out] = at[L,Out <: HList](implicit
    s: Selector[L,r: Replacer.Aux[L,(List[A],Out)]
  ): Case.Aux[L,as) => acc.updatedElem[List[A],Out](acc.select[List[A]] ++ as)
  }
}

def magic[L <: HList](l: L)(implicit f: LeftFolder[L,HNil,combine.type]) =
  l.foldLeft(HNil: HNil)(combine)

主要区别在于新导入,但由于updatedElem上的额外类型参数,您还需要进行一些其他小的更改.

(编辑:李大同)

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

    推荐文章
      热点阅读