使用通用特征的子类映射 HList [英] Mapping over HList with subclasses of a generic trait

查看:42
本文介绍了使用通用特征的子类映射 HList的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将 poly1 函数映射到无形的 HList.它的元素是参数化特征的子类.但是,我收到错误找不到映射器的隐式值".这是一个基本示例:

I'm trying to map a poly1 function over a shapeless HList. Its elements are subclasses of a parameterised trait. However, I get the error "couldn't find implicit value for the Mapper". Here's a basic example:

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) 找不到参数 m 的隐式值:shapeless.ops.hlist.Mapper.Aux[pour.type,Proc.I,Proc.Req]

虽然这看起来像一个简单的问题,但我还没有在其他答案中找到(或认可)解决方案.我目前的解决方法是在 poly 中为 Drink 的每个子类定义一个案例.这显然不适用于 trait 的许多子类.有没有更好的解决方案(也许使用 TypeTags)?

Although this appears like a simple problem, I haven't found (or recognised) a solution in other answers. My current workaround is to define a case, in poly, for each subclass of Drink. This is obviously not appropriate with many subclasses of the trait. Could there be a better solution (perhaps with TypeTags)?

更新

对于任何(合理的)Poly1 函数,这个问题的一般答案由@Jasper_M 给出.(该问题在 使用具有不变容器的无形状 HLists 中进一步概括.)对于具体转换I =>Req 在上面的例子中一个更简单的解决方案是

A general answer to this question, for any (reasonable) Poly1 function, is given by @Jasper_M. (The question is further generalised in Using shapeless HLists with invariant containers.) For the specific transformation I => Req in the above example a simpler solution is

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 会导致隐式未找到"错误.)

which gives 10 :: 15.0 :: 1.0 :: HNil. (Note that productElements is wrongly flagged as error in Intellij 2017.2.6. Moreover, the "untupled" version drinks flatMap identity causes an "implicit not found" error.)

推荐答案

尝试使用多态方法:

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)
}

这篇关于使用通用特征的子类映射 HList的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆