【问题标题】:mapping over HList inside a function映射到函数内的 HList
【发布时间】:2015-12-03 13:02:04
【问题描述】:

下面的代码看起来很明显,可以编译和运行

case class Pair(a: String, b: Int)

val pairGen = Generic[Pair]

object size extends Poly1 {
  implicit def caseInt = at[Int](x => 1)
  implicit def caseString = at[String](_.length)
}

def funrun(p: Pair) = { 
  val hp: HList = pairGen.to(p)
  hp.map(size)
}

但是编译器说“找不到参数映射器的隐式值”。在我的用例中,我想映射一个 HList 以获取 String(s) 的 HList,然后将 String(s) 的 HList 转换为 Scala List[String]。有任何想法吗?

【问题讨论】:

  • 如果您删除 hp 的类型,那么代码将照原样运行。因此,您应该使用“val hp = pairGen.to(p)”而不是“val hp: HList = pairGen.to(p)”

标签: scala shapeless type-level-computation hlist


【解决方案1】:

首先,我们可以创建一个类似于sizePoly1,我们可以使用它来将HList 映射到StringsHList

object strings extends Poly1 {
  implicit def caseInt = at[Int](_.toString)
  implicit def caseString = at[String](identity)
}

您已经使用Generic[Pair]Pair 转换为HList,但您无法映射您的hp,因为您的funrun 中没有证据表明您可以映射它。我们可以通过使用隐式参数来解决这个问题。

def funRun[L <: HList, M <: HList](
  p: Pair
)(implicit
  gen: Generic.Aux[Pair, L],
  mapper: Mapper.Aux[strings.type, L, M]
) = gen.to(p).map(strings)
  • 我们的第一个隐式参数gen 可以将Pair 变成HList L 类型。
  • 我们的第二个隐式参数mapper 可以使用我们的strings 多态函数将HList 类型的L 映射到HList 类型的M

我们现在可以使用funRunPair 变成HListStrings

scala> funRun(Pair("abc", 12))
res1: shapeless.::[String,shapeless.::[String,shapeless.HNil]] = abc :: 12 :: HNil

但您想返回 List[String]。要将我们的HListM(映射到String的结果)转换为List[String],我们需要一个ToTraversable,因此我们添加了第三个隐式参数:

import shapeless._, ops.hlist._

def pairToStrings[L <: HList, M <: HList](
  p: Pair
)(implicit
  gen: Generic.Aux[Pair, L],
  mapper: Mapper.Aux[strings.type, L, M],
  trav: ToTraversable.Aux[M,List,String]
): List[String] = gen.to(p).map(strings).toList

我们可以用作:

scala> pairToStrings(Pair("abc", 12))
res2: List[String] = List(abc, 12)

【讨论】:

  • 谢谢@Peter!这正是我想要的!
  • 关闭此线程后,我一直在兜圈子,试图理解为什么以下对复合类型的基本增强不起作用:`class A[T](val x: T);对象 g 扩展 Poly1 { 隐式 def caseString = at[String] { identity } }; def toStr[L <: hlist a: a gen: generic.aux l mapper: mapper gen.to .map>
  • 我收到了could not find implicit value for parameter mapper: shapeless.ops.hlist.Mapper[g.type,gen.Repr]
  • 你导入shapeless.ops.hlist._了吗?
  • 导入shapeless.ops.hlist._ 使上面的代码工作。谢谢@彼得!我的用例还有一个额外的转折——可变参数列表。此代码编译 REPL:` case class A[T](a: T) case class As(as: A[String]*) object f extends Poly1 {implicit def caseA = at[A[String]](identity) } def toStr[L <: hlist m as: as gen: generic.aux l mapper: mapper.aux gen.to val a='A[String]("one")'>. BUT the call to toStr(as)` 像以前一样给出映射器错误。
猜你喜欢
  • 2012-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 2017-02-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多