函数推断HLists的压缩类型

4
感谢https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0,我现在知道如何将shapeless HLists压缩起来了:
从Shapeless 2.0.0-M1导入一些内容:
import shapeless._
import shapeless.ops.hlist._
import syntax.std.tuple._
import Zipper._

创建两个HList:
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))?

我的最终目的是定义一个函数,将这两个HList捆绑在一起,并对它们进行映射,根据抛硬币结果选择_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)

但是当我尝试将其放入函数中时,上述问题令我困扰。

谢谢!


2
我现在不在电脑旁,但是Unit问题已经在第一个里程碑之后被修复了。现在那些例子将无法编译,并且错误信息应该会告诉你需要添加到方法定义中的Zip实例。 - Travis Brown
谢谢,Travis。我现在使用2.0.0-SNAPSHOT时遇到了一个错误。我可能仍需要一两个提示来完成我的目标,但这个新的错误很有帮助。 - Adam Pingel
特别地,定义f如上所示后的错误是: <console>:24: 错误:找不到参数transpose的隐式值:shapeless.ops.tuple.Transposer[(HL, HL)] def f[HL <: HList](h1: HL, h2: HL) = (h1, h2).zip - Adam Pingel
2个回答

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

现在假设您已经像问题中定义了h1h2,您可以编写以下代码:

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或最新的快照中起作用,尽管(正如我在上面的评论中指出的),在此错误被修复之前,您可能会遇到困惑的问题。


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接