scanLeft使用HMap无形

时间:2016-11-02 09:42:52

标签: scala shapeless

我使用无形HMap作为案例类的底层结构,充当共享同一父级的其他对象的聚合器。父特征允许访问名为arity的Int值属性。我想在scanLeft上使用HMap来计算arity中对象的累积HList。我成功编写了Poly个对象,允许使用arity计算所有foldLeft的总和,但在尝试将相同的概念应用于scanLeft时,它不会再努力了。

问题1:有人看到我应该如何修改pointAccumulate以支持scanLeft操作吗?我希望lookup类似Nat(2) :: Nat(5) :: Nat(8) :: HNil(使用下面的示例)。

Q2:之后我将使用lookup来搜索已知组合结构中累积arity的元素的索引。鉴于此,是否可以使用HList,或者我应该确保将lookup作为List [Int]?

import shapeless._
import ops.hlist.{At, LeftFolder, LeftScanner}

object Point { type Point = (Double, Double) }

import Point._

sealed trait Shape {
    val arity: Int
}

case class Line(p0: Point, p1: Point) extends Shape {
    val arity = 2
}

case class Triangle(p0: Point, p1: Point, p2: Point) extends Shape {
    val arity = 3
}

case class Canvas[L <: HList](shapes: L)
                             (implicit
                              val ev: LUBConstraint[L, Shape],
                              val lf: LeftFolder.Aux[L, Int, pointAccumulate.type, Int],
                              val ls: LeftScanner[L, Int, pointAccumulate.type]) {

    lazy val parameterCount: Int = shapes.foldLeft(0)(pointAccumulate)

    lazy val lookup = shapes.scanLeft(0)(pointAccumulate)
}

object pointCount extends Poly1 {
    implicit def default[T <: Shape] = at[T](_.arity)
}

object pointAccumulate extends Poly2 {
    implicit def default[T <: Shape](implicit pt: pointCount.Case.Aux[T, Int]) =
        at[Int, T] { (i, p) => i + pointCount(p) }
}

object App {

    def main(args: Array[String]): Unit = {

        val l0 = Line((-2, 2), (2, -2))
        val tr1 = Triangle((0,0), (0, 1), (1, 0))
        val tr2 = Triangle((1,1), (1, 2), (2, 1))

        val c = Canvas(l0 :: tr1 :: tr2 :: HNil)
        println(c.lookup)
    }
}

1 个答案:

答案 0 :(得分:0)

我设法使用@devkat中的提示解决了这个问题。这是代码的工作

import shapeless._
import ops.hlist.{At, LeftFolder, LeftScanner}

object Point { type Point = (Double, Double) }

import Point._

sealed trait Shape {
    val arity: Int
}

case class Line(p0: Point, p1: Point) extends Shape {
    val arity = 2
}

case class Triangle(p0: Point, p1: Point, p2: Point) extends Shape {
    val arity = 3
}

case class Canvas[L <: HList, LL <: HList](shapes: L)
                             (implicit
                              val ev: LUBConstraint[L, Shape],
                              val lf: LeftFolder.Aux[L, Int, pointAccumulate.type, Int],
                              val ls: LeftScanner.Aux[L, Int, pointAccumulate.type, LL],
                              val ev2: LUBConstraint[LL, Int]) {

    lazy val parameterCount: Int = shapes.foldLeft(0)(pointAccumulate)

    lazy val lookup = shapes.scanLeft(0)(pointAccumulate)
}

object pointCount extends Poly1 {
    implicit def default[T <: Shape] = at[T](_.arity)
}

object pointAccumulate extends Poly2 {
    implicit def default1[T <: Shape](implicit pt: pointCount.Case.Aux[T, Int]) =
        at[T, Int] { (p, i) => i + pointCount(p) }

    implicit def default2[T <: Shape](implicit pt: pointCount.Case.Aux[T, Int]) =
        at[Int, T] { (i, p) => i + pointCount(p) }
}

object App2 {

    def main(args: Array[String]): Unit = {

        val l0 = Line((-2, 2), (2, -2))
        val tr1 = Triangle((0,0), (0, 1), (1, 0))
        val tr2 = Triangle((1,1), (1, 2), (2, 1))

        val c = Canvas(l0 :: tr1 :: tr2 :: HNil)
        println(c.parameterCount)
        println(c.lookup)
    }
}