gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 13:27:24 25 4
gpt4 key购买 nike

我有一个具有以下结构的无形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中有一些内置功能吗?

最佳答案

尽管其他答案中的方法(引入新类型的类)可以工作,但可以使用更通用的机制来解决此问题,并且这种方式与您在值(value)水平上解决类似问题的方式没有什么不同。

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

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, 2, 3, 4, 5) :: List('a, 'b) :: List("X", "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, List[A], Out] = at[L, List[A]](_ :+ _)
}

object combine extends LowPriorityCombine {
implicit def alreadySeen[L <: HList, A, Out <: HList](implicit
s: Selector[L, List[A]],
r: Replacer.Aux[L, List[A], List[A], (List[A], Out)]
): Case.Aux[L, List[A], Out] = at[L, List[A]] {
case (acc, 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上的额外类型参数,您还需要进行一些其他小的更改。

关于scala - 将无形的HList转换为较小的HList,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20640847/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com