首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用具有不变容器的无形状HLists

使用具有不变容器的无形状HLists
EN

Stack Overflow用户
提问于 2018-01-08 14:49:42
回答 1查看 148关注 0票数 1

假设HList的元素是泛型特征的子类。每个元素都包含在case class Box[E](elem E)中。BoxE中是不变的,这会导致在HList上映射poly1、根据其父特性选择元素等方面的问题。

代码语言:javascript
复制
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的答案应用于Mapping over HList with subclasses of a generic trait

这段代码通向Error:(38, 22) could not find implicit value for parameter m: shapeless.ops.hlist.Mapper.Aux[pour.type,Proc.I,Proc.O] Proc.make()。另外,过滤Proc.drinks.covariantFilter[Box[Drink[Int]]]会产生HNil。(这个过滤器实现了@Travis到Do a covariant filter on an HList的答案。)

在我的项目中,定义解决问题的Box[+E]是不可能的。一个天真的解决方案--在pour中为Drink的每个子类设置一个大小写--不会扩展。(这可以通过将单纯函数传递给pour (我不知道如何实现)来实现。

在这个设置中,是否有一种更合理的方法来映射或过滤HLists?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-01-08 15:30:29

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

代码语言:javascript
复制
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也是多态的,那么您还可以更进一步:

代码语言:javascript
复制
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限制的多态性,但这可能会使我们走得太远。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48152668

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档