使用通用特征的子类映射 HList
Mapping over HList with subclasses of a generic trait
我正在尝试将 poly1 函数映射到无形 HList 上。它的元素是参数化特征的子类。但是,我收到错误 "couldn't find implicit value for the Mapper"。这是一个基本示例:
import shapeless._
trait Drink[+A]{
def v: A
}
case class Water(v: Int) extends Drink[Int]
case class Juice(v: BigDecimal) extends Drink[BigDecimal]
case class Squash(v: BigDecimal) extends Drink[BigDecimal]
object pour extends Poly1{
implicit def caseInt: Case.Aux[Drink[Int], Int] =
at(o => o.v)
implicit def caseDec: Case.Aux[Drink[BigDecimal], BigDecimal] =
at(o => o.v)
}
object Proc {
type I = Water ::Squash ::Juice :: HNil
type Req = Int ::BigDecimal ::BigDecimal :: HNil
val drinks: I = Water(10)::Squash(15.0):: Juice(1.0)::HNil
def make()(implicit m: ops.hlist.Mapper.Aux[pour.type, I, Req]): Req = { drinks.map(pour)}
}
运行 此代码生成
Error:(21, 27) could not find implicit value for parameter m: shapeless.ops.hlist.Mapper.Aux[pour.type,Proc.I,Proc.Req]
虽然这看起来像一个简单的问题,但我还没有在其他答案中找到(或识别)解决方案。我当前的解决方法是在 poly
中为 Drink
的每个子类定义一个案例。这显然不适用于特征的许多子类。
是否有更好的解决方案(也许使用 TypeTags)?
更新
对于任何(合理的)Poly1
函数,这个问题的一般答案由@Jasper_M 给出。 (这个问题在 中被进一步概括。)对于上面示例中的特定转换 I => Req
,一个更简单的解决方案是
import syntax.std.tuple._
import poly._
def makeTwo(): Req = (drinks.tupled flatMap identity).productElements
得到 10 :: 15.0 :: 1.0 :: HNil
。 (请注意 productElements
在 Intellij 2017.2.6 中被错误标记为错误。此外,"untupled" 版本 drinks flatMap identity
会导致 "implicit not found" 错误。)
尝试使用多态方法:
object pour extends Poly1{
implicit def caseInt[A <: Drink[Int]] =
at[A](o => o.v)
implicit def caseDec[A <: Drink[BigDecimal]] =
at[A](o => o.v)
}
我正在尝试将 poly1 函数映射到无形 HList 上。它的元素是参数化特征的子类。但是,我收到错误 "couldn't find implicit value for the Mapper"。这是一个基本示例:
import shapeless._
trait Drink[+A]{
def v: A
}
case class Water(v: Int) extends Drink[Int]
case class Juice(v: BigDecimal) extends Drink[BigDecimal]
case class Squash(v: BigDecimal) extends Drink[BigDecimal]
object pour extends Poly1{
implicit def caseInt: Case.Aux[Drink[Int], Int] =
at(o => o.v)
implicit def caseDec: Case.Aux[Drink[BigDecimal], BigDecimal] =
at(o => o.v)
}
object Proc {
type I = Water ::Squash ::Juice :: HNil
type Req = Int ::BigDecimal ::BigDecimal :: HNil
val drinks: I = Water(10)::Squash(15.0):: Juice(1.0)::HNil
def make()(implicit m: ops.hlist.Mapper.Aux[pour.type, I, Req]): Req = { drinks.map(pour)}
}
运行 此代码生成
Error:(21, 27) could not find implicit value for parameter m: shapeless.ops.hlist.Mapper.Aux[pour.type,Proc.I,Proc.Req]
虽然这看起来像一个简单的问题,但我还没有在其他答案中找到(或识别)解决方案。我当前的解决方法是在 poly
中为 Drink
的每个子类定义一个案例。这显然不适用于特征的许多子类。
是否有更好的解决方案(也许使用 TypeTags)?
更新
对于任何(合理的)Poly1
函数,这个问题的一般答案由@Jasper_M 给出。 (这个问题在 I => Req
,一个更简单的解决方案是
import syntax.std.tuple._
import poly._
def makeTwo(): Req = (drinks.tupled flatMap identity).productElements
得到 10 :: 15.0 :: 1.0 :: HNil
。 (请注意 productElements
在 Intellij 2017.2.6 中被错误标记为错误。此外,"untupled" 版本 drinks flatMap identity
会导致 "implicit not found" 错误。)
尝试使用多态方法:
object pour extends Poly1{
implicit def caseInt[A <: Drink[Int]] =
at[A](o => o.v)
implicit def caseDec[A <: Drink[BigDecimal]] =
at[A](o => o.v)
}