Scalaz 自动类型类解析

标签 scala functional-programming typeclass scalaz

我有几个 Map[String, String] 并希望合并它们以使值保持不变。默认情况下,Map semigroup 将连接字符串,因此我使用 Tags.LastVal。 目前我正在做以下事情:

m1.mapValues(Tags.LastVal) |+| m2.mapValues(Tags.LastVal)

这个映射看起来冗长乏味。 我可以以某种方式告诉编译器在范围内使用特定的半组,例如 Semigroup[Map[K, V @@ LastVal] 而不是默认的?

最佳答案

是的,您可以将您想要的实例隐含在您需要的范围内,编译器会找到它:

import scalaz._, Scalaz._

def mergeWithReplace(m1: Map[String, String], m2: Map[String, String]) = {
  implicit val stringInstance: Semigroup[String] = Semigroup.lastSemigroup
  m1 |+| m2
}

然后:

scala> mergeWithReplace(Map("a" -> "foo", "b" -> "qux"), Map("a" -> "bar"))
res0: Map[String,String] = Map(a -> bar, b -> qux)

即使不考虑一致性的理论论证,这也是令人烦恼且脆弱的。例如,隐式的名称必须是 stringInstance为了隐藏从 scalaz.std.string 导入的隐式内容,因为该类型具有更具体的类型,即使您不要求更具体的类型。我不记得这种优先行为是否有某种借口,而且我真的不想关心,所以我倾向于避免使用这样的本地实例。

不过,在这种情况下,恰好有一个更好的解决方案。 Scalaz 提供 Plus map 实例,以及 Plus不知道值类型,因此它通过选择最后一个来组合值。这意味着您可以通过使用<+>来获得您想要的东西。来自 Plus 的运算符:

def mergeWithReplace(m1: Map[String, String], m2: Map[String, String]) =
  m1 <+> m2

然后:

scala> mergeWithReplace(Map("a" -> "foo", "b" -> "qux"), Map("a" -> "bar"))
res0: scala.collection.immutable.Map[String,String] = Map(a -> bar, b -> qux)

不过,你通常不会那么幸运。

关于Scalaz 自动类型类解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34722320/

相关文章:

haskell - 如何在 Haskell 中添加/减去绝对值和相对值的运算符

haskell - 使用具有约束字段的数据类型代替约束

scala - 如何进行与硬件无关的并行编程?

multithreading - 线程安全的内存缓存

c# - 如何支持名义类型语言的结构类型?

functional-programming - curry 函数中的反向参数顺序(ramda js)

java - 分发库 Jar 时如何包含 scala 代码的 javadoc?

scala - 多态方法返回子类类型

haskell - 在整数列表中搜索,按增长排序的最长有序子集(不一定是连续的)之一

haskell - 依赖类约束的不明确类型变量