Scalaz Bind[Seq] typeclass
Asked Answered
L

1

5

I'm currently porting some code from traditional Scala to Scalaz style.

It's fairly common through most of my code to use the Seq trait in my exposed API signatures rather than a concrete type (i.e. List, Vector) directly. However, this poses some problem with Scalaz, since it doesn't provide an implementation of a Bind[Seq] typeclass.

i.e. This will work correctly.

List(1,2,3,4) >>= bindOperation

But this will not

Seq(1,2,3,4) >>= bindOperation

failing with the error could not find implicit value for parameter F0: scalaz.Bind[Seq]

I assume this is an intentional design decision in Scalaz - however am unsure about intended/best practice on how to precede.

Should I instead write my code directly to List/Vector as appropriate instead of using the more flexible Seq interface? Or should I simply define my own Bind[Seq] typeclass?

Larry answered 15/7, 2014 at 8:38 Comment(1)
There is a monad instance of IndexedSeq, though.Tatterdemalion
T
11

The collections library does backflips to accommodate subtyping: when you use map on a specific collection type (list, map, etc.), you'll (usually) get the same type back. It manages this through the use of an extremely complex inheritance hierarchy together with type classes like CanBuildFrom. It gets the job done (at least arguably), but the complexity doesn't feel very principled. It's a mess. Lots of people hate it.

The complexity is generally pretty easy to avoid as a library user, but for a library designer it's a nightmare. If I provide a monad instance for Seq, that means all of my users' types get bumped up the hierarchy to Seq every type they use a monadic operation.

Scalaz folks tend not to like subtyping very much, anyway, so for the most part Scalaz stays around the leaves of the hierarchy—List, Vector, etc. You can see some discussion of this decision on the mailing list, for example.

When I first started using Scalaz I wrote a lot of utility code that tried to provide instances for Seq, etc. and make them usable with CanBuildFrom. Then I stopped, and now I tend to follow Scalaz in only ever using List, Vector, Map, and Set in my own code. If you're committed to "Scalaz style", you should do that as well (or even adopt Scalaz's own IList, ISet, ==>>, etc.). You're not going to find clear agreement on best practices more generally, though, and both approaches can be made to work, so you'll just need to experiment to find which you prefer.

Terrill answered 15/7, 2014 at 11:58 Comment(2)
Is this also the reason e.g. scalaz.NonEmptyList[T] is not a subtype of Seq[T]?Tatterdemalion
@rightfold: Yeah, and I wouldn't be too surprised if NonEmptyList becomes invariant someday, which is another reason not to get stuck in the Seq swamp.Terrill

© 2022 - 2024 — McMap. All rights reserved.