使用具有不变容器的无形 HLists [英] Using shapeless HLists with invariant containers

查看:51
本文介绍了使用具有不变容器的无形 HLists的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设 HList 的元素是通用特征的子类.每个元素都包含在 case class Box[E](elem E) 中.BoxE 中是 invariant 会导致在 HList 上映射 poly1 时出现问题,通过其父特征等选择元素.这是一个例子:

Suppose the elements of an HList are subclasses of a generic trait. Each element is contained in case class Box[E](elem E). That Box is invariant in E causes problems with mapping a poly1 over HList, selecting an element by its parent trait, etc. Here's an 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]


case class Box[E](elem: E) // NB! invariance in E

object pour extends Poly1{

  implicit def caseInt[A <: Box[Drink[Int]]] =  at[A](o => Box(o.elem.v * 2))
  implicit def caseDec[A <: Box[Drink[BigDecimal]]] = at[A](o => Box(o.elem.v + 5.0))
}


object Proc {

  type I = Box[Water] :: Box[Squash] :: Box[Juice] ::  HNil
  type O = Box[Int] :: Box[BigDecimal] :: Box[BigDecimal] :: HNil

  val drinks: I = Box(Water(10)) :: Box(Squash(15.0)) :: Box(Juice(2.0)) :: HNil

  def make()(implicit m: ops.hlist.Mapper.Aux[pour.type, I, O]): O = drinks.map(pour)
}


object Main extends App{
  override def main(args: Array[String]): Unit =  Proc.make()
}

*函数 pour 将@Jasper_M 的答案应用到 使用泛型特征的子类映射 HList.

*The function pour applies the answer by @Jasper_M to Mapping over HList with subclasses of a generic trait.

这段代码导致Error:(38, 22) 找不到参数 m 的隐含值:shapeless.ops.hlist.Mapper.Aux[pour.type,Proc.I,Proc.O]proc.make().此外,过滤 Proc.drinks.covariantFilter[Box[Drink[Int]]] 会产生 HNil.(此过滤器实现了@Travis Brown 对 在 HList 上执行协变过滤器的回答.)

This code leads to Error:(38, 22) could not find implicit value for parameter m: shapeless.ops.hlist.Mapper.Aux[pour.type,Proc.I,Proc.O] Proc.make(). Also, filtering Proc.drinks.covariantFilter[Box[Drink[Int]]] produces HNil. (This filter implements the answer by @Travis Brown to Do a covariant filter on an HList.)

定义解决问题的Box[+E],在我的项目中是不可能的.一个天真的解决方案——在 pour 中为 Drink 的每个子类都有一个案例——不能扩展.(这可以通过将单态函数传递给 pour 来实现,我不知道如何.)

Defining Box[+E], which solves the problems, is not possible in my project. A naive solution -- to have a case in the pour for each subclass of Drink -- does not scale. (This could be made to work by passing monomorphic functions to pour, which I don't know how.)

在此设置中是否有更明智的方法来映射或过滤 HList?

Could there be a more sensible approach to mapping or filtering over HLists in this set-up?

推荐答案

在这种情况下,所有外部类型构造函数都是 Box,您可以应用与我之前的答案几乎相同的技术:

In this case where all your outer type constructors are Box, you can apply almost the same technique as in my previous answer:

object pour extends Poly1{
  implicit def caseInt[A <: Drink[Int]] =  at[Box[A]](o => Box(o.elem.v * 2))
  implicit def caseDec[A <: Drink[BigDecimal]] = at[Box[A]](o => Box(o.elem.v + 5.0))
}

现在如果你的 Box 类型也是多态的,你仍然可以更进一步:

Now if your type of Box is also polymorphic, you can still go a step further:

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]

trait Box[E] { def elem: E}
case class ABox[E](elem: E) extends Box[E]
case class BBox[E](elem: E) extends Box[E]

object pour extends Poly1{
  implicit def caseInt[A <: Drink[Int], M[x] <: Box[x]] = at[M[A]](o => o.elem.v * 2)
  implicit def caseDec[A <: Drink[BigDecimal], M[x] <: Box[x]] = at[M[A]](o => o.elem.v + 5.0)
}


val drinks = ABox(Water(10)) :: BBox(Squash(15.0)) :: ABox(Juice(2.0)) :: HNil

drinks.map(pour)

您可能已经注意到,在最后一个示例中,我没有将值重新包装在其框中.您仍然可以这样做,例如,如果您实现类似 trait Boxer[M[_]] { def box[A](a: A): M[A] } 类型类的东西,或者使用Box 中的 F 有界多态性,但这可能会让我们走得太远.

You may have noticed I didn't re-wrap the values in its box in this last example. You could still do that, for instance if you implement something like a trait Boxer[M[_]] { def box[A](a: A): M[A] } typeclass, or with F-bounded polymorphism in Box, but that would probably lead us too far.

这篇关于使用具有不变容器的无形 HLists的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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