chuwy
chuwy

Reputation: 6669

Scalaz automatic typeclass resolution

I have several Map[String, String] and want to merge them so values remain the same. By default Map semigroup will concatenate strings, so I'm using Tags.LastVal. Currently I'm doing following:

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

This mapping looks verbose and tedious. Can I somehow tell compiler to use specific Semigroup in the scope, like Semigroup[Map[K, V @@ LastVal] rather than default one?

Upvotes: 2

Views: 48

Answers (1)

Travis Brown
Travis Brown

Reputation: 139038

Yes, you can make the instance you want implicit in the scope you need and it'll be found by the compiler:

import scalaz._, Scalaz._

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

And then:

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

Even apart from theoretical arguments for coherence, though, this is annoying and fragile. For example, the name of the implicit must be stringInstance in order to shadow the implicit that was imported from scalaz.std.string, since that one has a more specific type, even though you're not asking for a more specific type. I don't remember whether there's some excuse for that precedence behavior, and I don't really want to have to care, so I tend to avoid using local instances like that.

In this case there happens to be a nicer solution, though. Scalaz provides Plus instances for maps, and Plus doesn't know about the value type, so it combines values by picking the last one. This means you can get what you want by using the <+> operator from Plus:

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

And then:

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

You're not usually going to get that lucky, though.

Upvotes: 2

Related Questions