在 scalaz 中定义你自己的半群
Define your own semigroup in scalaz
我想在 Scala 中合并两个映射,给出一个用于组合值的特定函数。
我很喜欢map1 |+| scalaz 中的 map2,但是我找不到用其他东西替换 + 的方法。例如,我想为每个键选择最大值或最小值。理想情况下,运算符将作为外部函数提供,因此类似于:
def op (a, b) = min(a,b)
map1 |op| map2
这将为所有键提供来自两个映射的相应最小值。
Map
半群使用半群作为其值类型来合并每个键的值。如果您想要不同的行为,您可以只对半群具有不同行为的值使用类型包装器。
import scalaz._, Scalaz._
val map1 = Map("foo" → 1, "bar" → 2)
val map2 = Map("foo" → 3)
val default = map1 |+| map2
// Map(foo → 4, bar → 2): Map[String, Int]
val min = map1.mapValues(Tags.MinVal(_)) |+| map2.mapValues(Tags.MinVal(_))
// Map(foo → 1, bar → 2): Map[String, Int @@ Tags.MinVal]
您可以使用 .unwrap
“展开”标记值
import scalaz.syntax.tag._
min.mapValues(_.unwrap)
// Map(foo → 1, bar → 2): Map[String, Int]
创建您自己的类型包装器非常简单。您只需将您的类型包装在另一个具有适当定义的类型 class 实例的类型中。例如,如果您想创建自己的 Tags.MaxVal
版本,您可以这样写:
case class Max[A: Order](unwrap: A)
object Max {
implicit def semigroup[A: Order]: Semigroup[Max[A]] =
new Semigroup[Max[A]] {
def append(f1: Max[A], f2: ⇒ Max[A]) =
Max(Order[A].max(f1.unwrap, f2.unwrap))
}
}
val max = map1.mapValues(Max(_)) |+| map2.mapValues(Max(_))
max.mapValues(_.unwrap)
// Map(foo → 3, bar → 2): Map[String, Int]
或者,用户可以使用 Scalaz Tag
东西以类似的方式定义包装器;有关此示例,请参阅 scalaz.Tag
、scalaz.Tags
和 scalaz.std.AnyValInstances
。
我想在 Scala 中合并两个映射,给出一个用于组合值的特定函数。
我很喜欢map1 |+| scalaz 中的 map2,但是我找不到用其他东西替换 + 的方法。例如,我想为每个键选择最大值或最小值。理想情况下,运算符将作为外部函数提供,因此类似于:
def op (a, b) = min(a,b)
map1 |op| map2
这将为所有键提供来自两个映射的相应最小值。
Map
半群使用半群作为其值类型来合并每个键的值。如果您想要不同的行为,您可以只对半群具有不同行为的值使用类型包装器。
import scalaz._, Scalaz._
val map1 = Map("foo" → 1, "bar" → 2)
val map2 = Map("foo" → 3)
val default = map1 |+| map2
// Map(foo → 4, bar → 2): Map[String, Int]
val min = map1.mapValues(Tags.MinVal(_)) |+| map2.mapValues(Tags.MinVal(_))
// Map(foo → 1, bar → 2): Map[String, Int @@ Tags.MinVal]
您可以使用 .unwrap
import scalaz.syntax.tag._
min.mapValues(_.unwrap)
// Map(foo → 1, bar → 2): Map[String, Int]
创建您自己的类型包装器非常简单。您只需将您的类型包装在另一个具有适当定义的类型 class 实例的类型中。例如,如果您想创建自己的 Tags.MaxVal
版本,您可以这样写:
case class Max[A: Order](unwrap: A)
object Max {
implicit def semigroup[A: Order]: Semigroup[Max[A]] =
new Semigroup[Max[A]] {
def append(f1: Max[A], f2: ⇒ Max[A]) =
Max(Order[A].max(f1.unwrap, f2.unwrap))
}
}
val max = map1.mapValues(Max(_)) |+| map2.mapValues(Max(_))
max.mapValues(_.unwrap)
// Map(foo → 3, bar → 2): Map[String, Int]
或者,用户可以使用 Scalaz Tag
东西以类似的方式定义包装器;有关此示例,请参阅 scalaz.Tag
、scalaz.Tags
和 scalaz.std.AnyValInstances
。