scalaz Monoid for SortedMap

82 Views Asked by At

I believe scalaz has monoid instances for both Map and SortedMap.

But this doesn't work

scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._

scala> Map(1 -> 1) |+| Map(1 -> 1)
res0: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2)

scala> import scala.collection.SortedMap
import scala.collection.SortedMap

scala> SortedMap(1 -> 1) |+| SortedMap(1 -> 1)
<console>:19: error: value |+| is not a member of scala.collection.SortedMap[Int,Int]
       SortedMap(1 -> 1) |+| SortedMap(1 -> 1)
                         ^
2

There are 2 best solutions below

1
Kenji Yoshida On BEST ANSWER

Scalaz provide immutable data structure instances only.

You should add import scalaz.std.sortedMap._ and use scala.collection.immutable.SortedMap instaead of scala.collection.SortedMap.

Welcome to Scala 2.13.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_201).
Type in expressions for evaluation. Or try :help.

scala> scalaz.BuildInfo
res0: scalaz.BuildInfo.type = version: 7.2.30, scalaVersion: 2.13.1

scala> import scalaz.std.sortedMap._
import scalaz.std.sortedMap._

scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._

scala> scala.collection.SortedMap(1 -> 2) |+| scala.collection.SortedMap(1 -> 3)
                                          ^
       error: value |+| is not a member of scala.collection.SortedMap[Int,Int]
       did you mean ++:?

scala> scala.collection.immutable.SortedMap(1 -> 2) |+| scala.collection.immutable.SortedMap(1 -> 3)
res2: scala.collection.immutable.SortedMap[Int,Int] = TreeMap(1 -> 5)
3
Scalway On

Scalaz will use SortedMap if second argument is SortedMap (like scala collections do) but this is implementation detail and you should not rely on it.

//If you only care about `Map` inteface then treat `SortedMap` as normal `Map`: 
val res = Map(1 -> 1) |+| SortedMap(1 -> 1)
println(res.getClass.getName) // scala.collection.immutable.TreeMap

//If you really need to have access to SortedMap api then you can cast to it:
val res2 = res.asInstanceOf[SortedMap[Int, Int]]

EDITED This is implementation detail and you should be aware of that! There should be better answer to this question that uses existing scalaz implementation for sortedMap!

I've no time to investigate more ... sory.

key is here that we use to instance as a builder for result here.

//from implementation of |+|
from.foldLeft(to) { case (to, (k, v)) => to + ... }

shortly: Don't mark this answer as valid one: It is not. Probably you should not rely on implementation detail. Still it is possible and this answer could be helpful for someone.