2015-03-06 17 views
9

Shapeless'ı öğrenmeye çalışıyorum ve birlikte olmayan kayıt örneklerini ekleyen bir monoid tanımlamak istiyorum. Algebird monoids (scalaz değil) kullandığımı unutmayın, ama eminim ki oldukça benzerler. aşağıdaki gibiShapeless Records için bir Tipeclass tanımlayın

val result = Monoid.sum(
    ('a ->> 1) :: ('b ->> 1) :: HNil, 
    ('a ->> 4) :: ('b ->> 3) :: HNil, 
    ('a ->> 2) :: ('b ->> 6) :: HNil) 
// result should be: ('a ->> 7) :: ('b ->> 10) :: HNil 

Ben hList için monoid örneklerini yazmak için nasıl düşündüm: Bu veriyor

implicit val HNilGroup: Group[HNil] = new ConstantGroup[HNil](HNil) 
    implicit val HNilMonoid: Monoid[HNil] = HNilGroup 
    class HListMonoid[H, T <: HList](implicit hmon: Monoid[H], tmon: Monoid[T]) extends Monoid[::[H, T]] { 
    def zero = hmon.zero :: tmon.zero 
    def plus(a: ::[H, T], b: ::[H, T]) = 
     hmon.plus(a.head, b.head) :: tmon.plus(a.tail, b.tail) 
    } 
    implicit def hListMonoid[H, T <: HList](implicit hmon: Monoid[H], tmon: Monoid[T]) = new HListMonoid[H, T] 

yazmamı: İşte yapabilmek ne istiyorsunuz bir örnek

Ben hList örneklerini özetleyebilirim olduğunu Şimdi
val result = Monoid.sum(
    1 :: 1 :: HNil, 
    4 :: 3 :: HNil, 
    2 :: 6 :: HNil) 
// result is 7 :: 10 :: HNil 

, eksik parçası benim IDE bana şu türe sahip söyler formu ('name ->> 1), alanlarını özetleyebilirim monoid örneklerini tanımlayan gibi görünüyor: Int with record.KeyTag[Symbol with tag.Tagged[Constant(name).type] { .. }, Int] { .. }. Bu noktada sıkışıp kaldım, çünkü bunu nasıl yapacağımı bilmiyorum.

cevap

11

Sen orada çok yakın sen-sadece yerine H her endüktif adımda FieldType[K, H] eklemek ve uygun Monoid[H] aldığım değerleri yazmak için field[K] kullanmak gerekir:

import com.twitter.algebird._ 
import shapeless._, labelled._, record._, syntax.singleton._ 

implicit val hnilGroup: Group[HNil] = new ConstantGroup[HNil](HNil) 
implicit val hnilMonoid: Monoid[HNil] = hnilGroup 
implicit def hconsMonoid[K, H, T <: HList](implicit 
    hm: Monoid[H], 
    tm: Monoid[T] 
): Monoid[FieldType[K, H] :: T] = 
    Monoid.from(field[K](hm.zero) :: tm.zero) { 
    case (hx :: tx, hy :: ty) => field[K](hm.plus(hx, hy)) :: tm.plus(tx, ty) 
    } 

Yoksa şekilsiz en TypeClass makineleri kullanabilirsiniz Ayrıca bu yapar burada derivedRecordInstance yöntem sağladık

import com.twitter.algebird._ 
import shapeless._, ops.hlist._, ops.record._, record._, syntax.singleton._ 

object MonoidHelper extends ProductTypeClassCompanion[Monoid] { 
    object typeClass extends ProductTypeClass[Monoid] { 
    def emptyProduct: Monoid[HNil] = Monoid.from[HNil](HNil)((_, _) => HNil) 
    def product[H, T <: HList](hm: Monoid[H], tm: Monoid[T]): Monoid[H :: T] = 
     Monoid.from(hm.zero :: tm.zero) { 
     case (hx :: tx, hy :: ty) => hm.plus(hx, hy) :: tm.plus(tx, ty) 
     } 

    def project[F, G](m: => Monoid[G], to: F => G, from: G => F): Monoid[F] = 
     Monoid.from(from(m.zero))((x, y) => from(m.plus(to(x), to(y)))) 
    } 

    implicit def deriveRecordInstance[ 
    R <: HList, 
    K <: HList, 
    H, 
    T <: HList 
    ](implicit 
    vs: Values.Aux[R, H :: T],   
    vm: Lazy[Monoid[H :: T]], 
    ks: Keys.Aux[R, K], 
    zk: ZipWithKeys.Aux[K, H :: T, R] 
): Monoid[R] = typeClass.project(vm.value, vs(_), zk(_: H :: T)) 
} 

import MonoidHelper._ 

vaka sınıflar için size örneklerini vb .: veren Kayıtlar üzerinde çalışıyorum ama biraz gerekli olduğuna şaşıyorum - Shapeless'in gelecekteki bir sürümünde kayıt örneklerini ücretsiz olarak alabilmeniz mümkün.

+0

Yardımın için teşekkürler, ilk çözüm benim için hile yaptı. Eminim ikinci örnek de çalışır, ama bunu anlamak için biraz daha araştırmam gerekecek. Shapeless 'auto typeclass türevini kullanmayı öğrenmeye çalışıyorum, ama şimdilik bu kod benim için oldukça opak. – JimN

İlgili konular