sch*_*mmd 5 monads scala scalaz monoids
我想写一个方法mergeKeys,Iterable[(K, V)]通过键将值组合在一起.例如,我可以写:
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)))
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我希望能够使用any Monoid而不是编写方法List.例如,值可能是整数,我想要对它们求和,而不是将它们附加到列表中.或者它们可能是元组(String, Int),我想在集合中累积字符串但添加整数.我怎么写这样的方法?或者还有什么我可以在scalaz中使用它来完成这项工作?
更新:我没有想象的那么遥远.我有点接近,但如果值是元组,我仍然不知道如何使它工作.我是否需要编写另一个隐式转换?即,每个类型参数的一个隐式转换?
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
}
Run Code Online (Sandbox Code Playgroud)
首先,虽然它与您的问题无关,但您通过明确提及类型构造函数来限制代码的通用性F[_].没有这样做,它工作正常:
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))
}
}
}
[...]
Run Code Online (Sandbox Code Playgroud)
现在,对于你的实际问题,没有必要改变mergeKeys来处理有趣的组合; 只需写一个Monoid来处理你想要做的任何组合.假设你想做你的Strings + Ints例子:
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
}
Run Code Online (Sandbox Code Playgroud)
给
Map(a -> (Hello, World,32), b -> (Goodbye, ,30))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
634 次 |
| 最近记录: |