2012-03-15 20 views
5

ile bir anahtarla grup değerleri Gruplar, Iterable[(K, V)] numaralı anahtarlardaki değerleri gruplayan bir mergeKeys yöntemi yazmak istiyorum. Örneğin, ben yazabilirsiniz:Herhangi bir Monoid

def mergeKeysList[K, V](iter: Iterable[(K, V)]) = { 
    iter.foldLeft(Map[K, List[V]]().withDefaultValue(List.empty[V])) { 
     case (map, (k, v)) => 
      map + (k -> (v :: map(k))) 
    } 
    } 

Ancak, ben List için bir yöntem yazmak yerine herhangi Monoid kullanabilmek için istiyorum. Örneğin, değerler tamsayı olabilir ve bunları bir listeye eklemek yerine bunları toplamak istiyorum. Ya da dizeleri (String, Int) olabilir, burada dizeleri bir kümede biriktirmek ama tamsayıları eklemek istiyorum. Böyle bir yöntemi nasıl yazabilirim? Yoksa bunu yapmak için scalazda kullanabileceğim başka bir şey var mı?

Güncelleme: Düşündüğüm kadar uzak değildim. Biraz daha yakınım, ama değerler tuples ise nasıl çalışacağını hala bilmiyorum. Başka bir gizli dönüşüm yazmam gerekiyor mu? Yani, her tip parametre için bir örtük dönüşüm mü? sorunuzun ilgili olmasa da

sealed trait SuperTraversable[T, U, F[_]] 
extends scalaz.PimpedType[TraversableOnce[(T, F[U])]] { 
    def mergeKeys(implicit mon: Monoid[F[U]]): Map[T, F[U]] = { 
    value.foldLeft(Map[T, F[U]]().withDefaultValue(mon.zero)) { 
     case (map, (k, v)) => 
     map + (k -> (map(k) |+| v)) 
    } 
    } 
} 

implicit def superTraversable[T, U, F[_]](
    as: TraversableOnce[(T, F[U])] 
): SuperTraversable[T, U, F] = 
    new SuperTraversable[T, U, F] { 
     val value = as 
    } 

cevap

6

Birincisi, açıkça tipi yapıcısı F[_] bahsederek kodun genelliği sınırlandırıyor. kombinasyonların komik türlü işlemek için mergeKeys değiştirmeye gerek yoktur,

sealed trait SuperTraversable[K, V] 
extends scalaz.PimpedType[TraversableOnce[(K, V)]] { 
    def mergeKeys(implicit mon: Monoid[V]): Map[K, V] = { 
     value.foldLeft(Map[K, V]().withDefaultValue(mon.zero)) { 
      case (map, (k, v)) => 
       map + (k -> (map(k) |+| v)) 
     } 
    } 
} 

[...] 

Şimdi, asıl soru için;: O kadar yapmadan ince işleri Sadece bir Monoid yazarak, yapmak istediğiniz birleştirme için türünü kullanın.

implicit def monoidStringInt = new Monoid[(String, Int)] { 
    val zero = ("", 0) 
    def append(a: (String, Int), b: => (String, Int)) = (a, b) match { 
     case ((a1, a2), (b1, b2)) => (a1 + b1, a2 + b2) 
    } 
} 

println { 
    List(
     "a" -> ("Hello, ", 20), 
     "b" -> ("Goodbye, ", 30), 
     "a" -> ("World", 12) 
    ).mergeKeys 
} 

Map(a -> (Hello, World,32), b -> (Goodbye, ,30)) 
+0

Mükemmel verir, teşekkür: Eğer Strings + Ints örnek yapmak istediği Say! – schmmd