scanLeft 在 shapeless 中使用 HMap
scanLeft using HMap in shapeless
我使用 shapeless HMap
作为案例的底层结构 class 作为共享同一父对象的其他对象的聚合器。 parent trait 允许访问一个名为 arity
的 Int 值 属性。我想在 HMap
上使用 scanLeft
来计算 HList
中对象的累积 arity
s。我成功地编写了 Poly
对象,允许使用 foldLeft
计算所有 arity
的总和,但是当尝试将相同的概念应用于 scanLeft
时,它并没有工作了。
Q1:有人看到我应该如何修改 pointAccumulate
以支持 scanLeft
操作吗?我期望 lookup
是这样的 Nat(2) :: Nat(5) :: Nat(8) :: HNil
(使用下面的示例)。
Q2:之后我将使用lookup
来搜索知道组合结构中累积数量的元素的索引。鉴于此,可以使用 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)
}
}
我使用@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)
}
}
我使用 shapeless HMap
作为案例的底层结构 class 作为共享同一父对象的其他对象的聚合器。 parent trait 允许访问一个名为 arity
的 Int 值 属性。我想在 HMap
上使用 scanLeft
来计算 HList
中对象的累积 arity
s。我成功地编写了 Poly
对象,允许使用 foldLeft
计算所有 arity
的总和,但是当尝试将相同的概念应用于 scanLeft
时,它并没有工作了。
Q1:有人看到我应该如何修改 pointAccumulate
以支持 scanLeft
操作吗?我期望 lookup
是这样的 Nat(2) :: Nat(5) :: Nat(8) :: HNil
(使用下面的示例)。
Q2:之后我将使用lookup
来搜索知道组合结构中累积数量的元素的索引。鉴于此,可以使用 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)
}
}
我使用@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)
}
}