再谈HLists的映射

3

我已经阅读了一些关于同样问题的Q&A,但似乎找不到适用于我的情况的解决方案。

本质上,我需要定义一个方法,该方法接受一个x(其中x <: T),以及一个l(其中L <: HList),并使用在每个可能从T继承的类中定义的Poly1对l进行映射。

我已经尝试了几种方式,但最后一次尝试导致了一些相当可怕的scalac bomb。 我一定做了什么非常愚蠢的事情,但似乎无法理解它!

import shapeless._
import ops.hlist._

trait T {
  val fun: Poly1
}
case class C() extends T {
  object fun extends Poly1 {
    implicit val caseInt = at[Int](i => "int " + i)
    override def toString = "here I am, poly1"
  }
}
def method[X <: T](x: X) = x.fun
method(C())
res0: shapeless.Poly1 = here I am, poly1

def method2[X <: T, L <: HList](x: X, l: L)(implicit m: Mapper[x.fun.type, L]) = l map x.fun
method(C(), 23 :: HNil) //BOOM!

正如我刚才在Twitter上提到的,你可能没那么幸运 - Travis Brown
@TravisBrown所说的... C()是易失性的,这会使对fun情况的隐式搜索变得困难。 - Miles Sabin
1个回答

1

我不确定这是否完全符合你的要求,但它可以工作:

object test {

import shapeless._
import ops.hlist._

  trait T {

    type PT <: Singleton with Poly1
    val fun: PT
  }

  object C extends T {

    type PT = funImpl.type
    object funImpl extends Poly1 {
      implicit val caseInt = at[Int](i => "int " + i)
      override def toString = "here I am, poly1"
    }
    val fun = funImpl
  }

  case class D() extends T {

    type PT = funImpl.type
    object funImpl extends Poly1 {
      implicit val caseInt = at[Int](i => "int " + i)
      override def toString = "here I am, poly1"
    }
    val fun = funImpl
  }


  def method[X <: T](x: X) = x.fun
  val ok = method(C)

  // singletonize it
  implicit def toOps[X <: T](x: X): Method2Ops[x.type] = { Method2Ops(x: x.type) }
  case class Method2Ops[X <: Singleton with T](val x: X) {

    def method2[L <: HList](l: L)(implicit m: Mapper[X#PT, L]) = l map (x.fun: X#PT)
  }

  val okC =  C method2 (23 :: HNil)

  val d = D()

  val okD = d method2 (23 :: HNil)
}

我可以说这个技巧的精髓在于隐式转换中传递 x: x.type,并且在 Method2Ops 中需要一个单例吗? 还有什么其他重要的地方吗? - laughedelic

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