感谢https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0我了解如何压缩无形的HLists:
从Shapeless 2.0.0-M1导入一些东西:
import shapeless._
import shapeless.ops.hlist._
import syntax.std.tuple._
import Zipper._
创建两个HLists:
scala> val h1 = 5 :: "a" :: HNil
h1: shapeless.::[Int,shapeless.::[String,shapeless.HNil]] = 5 :: a :: HNil
scala> val h2 = 6 :: "b" :: HNil
h2: shapeless.::[Int,shapeless.::[String,shapeless.HNil]] = 6 :: b :: HNil
拉链他们:
scala> (h1, h2).zip
res52: ((Int, Int), (String, String)) = ((5,6),(a,b))
现在尝试定义一个执行相同操作的函数:
scala> def f[HL <: HList](h1: HL, h2: HL) = (h1, h2).zip
f: [HL <: shapeless.HList](h1: HL, h2: HL)Unit
推断的返回类型是Unit,实际上将f应用于h1和h2就是这样:
scala> f(h1, h2)
scala>
有没有办法定义f,以便在这种情况下得到((5,6),(a,b))?
最终我要做的是定义一个拉伸两个HLists然后映射它们的函数,选择基于抛硬币的_1或_2,这将产生另一个HL。
object mix extends Poly1 {
implicit def caseTuple[T] = at[(T, T)](t =>
if (util.Random.nextBoolean) t._2 else t._1)
}
在REPL中可以正常工作:
scala> (h1, h2).zip.map(mix)
res2: (Int, String) = (5,b)
但是当我试图把它变成一个函数时,我正在惹恼上述问题。
谢谢!
答案 0 :(得分:7)
您可以使用Zip
(或本例Zip.Aux
)类型类在一个方法中包装所有内容:
import shapeless._, shapeless.ops.hlist._
object mix extends Poly1 {
implicit def caseTuple[T] = at[(T, T)](t =>
if (util.Random.nextBoolean) t._2 else t._1)
}
def zipAndMix[L <: HList, Z <: HList](h1: L, h2: L)(implicit
zipper: Zip.Aux[L :: L :: HNil, Z],
mapper: Mapper[mix.type, Z]
) = (h1 zip h2) map mix
现在假设您在问题中定义了h1
和h2
,您可以写下:
scala> zipAndMix(h1, h2)
res0: shapeless.::[Int,shapeless.::[String,shapeless.HNil]] = 5 :: b :: HNil
scala> zipAndMix(h1, h2)
res1: shapeless.::[Int,shapeless.::[String,shapeless.HNil]] = 6 :: a :: HNil
scala> zipAndMix(h1, h2)
res2: shapeless.::[Int,shapeless.::[String,shapeless.HNil]] = 5 :: a :: HNil
等等。这将在2.0.0-M1或最新快照中有效,尽管(正如我在上面的评论中所述),您可能会在this bug was fixed之前的路上遇到令人困惑的问题。
答案 1 :(得分:2)
鉴于编译器错误和一些在hlist.scala中进行测试的问题,zip是这样定义的:
def f[L <: HList, OutT <: HList](l : L)(
implicit transposer : Transposer.Aux[L, OutT],
mapper : Mapper[tupled.type, OutT]) = l.transpose.map(tupled)
我的mix
的应用可以这样定义:
def g[L <: HList](l : L)(
implicit mapper: Mapper[mix.type,L]) = l.map(mix)
构图符合我的要求:
scala> g(f(h1 :: h2 :: HNil))
res12: shapeless.::[Int,shapeless.::[String,shapeless.HNil]] = 5 :: b :: HNil
scala> g(f(h1 :: h2 :: HNil))
res13: shapeless.::[Int,shapeless.::[String,shapeless.HNil]] = 6 :: a :: HNil
scala> g(f(h1 :: h2 :: HNil))
res14: shapeless.::[Int,shapeless.::[String,shapeless.HNil]] = 6 :: b :: HNil