2016-11-02 1 views
1

Я использую бесформенный HMap как базовую структуру класса case, действующего как агрегатор для других объектов, имеющих один и тот же родитель. Родительский признак позволяет получить доступ к Int-значному свойству, которое называется arity. Я хотел бы использовать scanLeft на HMap для расчета совокупного arity с объектов в HList. Мне удалось записать объекты Poly, позволяющие рассчитать сумму всех arity с использованием foldLeft, но при попытке применить те же понятия к scanLeft он больше не работает.scanLeft с использованием HMap в бесформенном

Q1: Кто-нибудь видит, как я должен изменить pointAccumulate для поддержки scanLeft операций? Я ожидаю, что lookup будет чем-то вроде этого Nat(2) :: Nat(5) :: Nat(8) :: HNil (используя пример ниже).

Q2: Затем я буду использовать lookup для поиска индекса элемента, знающего совокупную значимость в объединенной структуре. Учитывая это, было бы нормально работать с HList или я должен убедиться, что получаю lookup в виде списка [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) 
    } 
} 
+0

Для 'scanLeft', то' параметры Poly2' должны быть включены: 'на [T], Int {(р, я) => г + pointCount (р)' – devkat

+0

@devat, вы правы, он работает с вашими изменениями. Спасибо за это! если вы хотите, вы можете добавить свой ответ в качестве ответа – sm01

ответ

0

Мне удалось решить это, используя подсказку от @devat. Вот рабочий кусок кода

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