【问题标题】:Inferred type of function that zips HLists压缩 HLists 的推断函数类型
【发布时间】:2013-12-08 18:07:00
【问题描述】:

感谢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._

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

但是当我试图将它拉入一个函数时,我被上述问题绊倒了。

谢谢!

【问题讨论】:

  • 我不在电脑旁,但Unit 问题是a bug that's been fixed since the first milestone。现在这些示例无法编译,错误消息应该告诉您需要添加到方法定义中的 Zip 实例。
  • 谢谢,特拉维斯。我现在在使用 2.0.0-SNAPSHOT 时看到一个错误。我可能仍然需要一两个提示来实现我的目标,但这个新错误很有帮助。
  • 具体如上图定义f后的错误为::24: error: could not find implicit value for parameter transpose: shapeless.ops.tuple.Transposer[(HL, HL) ] def f[HL <: hlist hl h2: h2>

标签: scala shapeless hlist


【解决方案1】:

您可以使用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 或最新快照,尽管(正如我在上面的评论中指出的那样)您可能会在 this bug was fixed 之前遇到令人困惑的问题。

【讨论】:

    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 2021-03-09
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 2019-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多