Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scalaz's Unapply: why doesn't traverseU work with State? Why must traverseS exist?

Usually Scalaz's Unapply does a pretty good job, but it seems to break down here with traverseU:

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

scala> val stateMonadInstance = unapplyMAB2[Monad, State, Int, Unit](IndexedStateT.stateMonad[Int]).TC
stateMonadInstance: scalaz.Monad[[X]scalaz.IndexedStateT[[+X]X,Int,Int,X]] = scalaz.StateTInstances1$$anon$1@27c591e1

scala> List(1, 2, 3).traverseU((i: Int) => stateMonadInstance.pure(i))
<console>:18: error: Unable to unapply type `scalaz.IndexedStateT[[+X]X,Int,Int,Int]` into a type constructor of kind `M[_]` that is classified by the type class `scalaz.Applicative`
1) Check that the type class is defined by compiling `implicitly[scalaz.Applicative[<type constructor>]]`.
2) Review the implicits in object Unapply, which only cover common type 'shapes'
(implicit not found: scalaz.Unapply[scalaz.Applicative, scalaz.IndexedStateT[[+X]X,Int,Int,Int]])
              List(1, 2, 3).traverseU((i: Int) => stateMonadInstance.pure(i))
                                     ^

The traverseS method seems to have been created as a workaround for this problem, whatever it is:

scala> List(1, 2, 3).traverseS((i: Int) => stateMonadInstance.pure(i))
res11: scalaz.State[Int,List[Int]] = scalaz.package$State$$anon$3@2634d0e2

But I'm trying to write a library which is generic with respect to the monad in question, so that's not a very good fit. Does anyone know what the exact problem is here that's preventing this from working, and if there's a workaround which doesn't require special-casing for State?

like image 918
Tom Crockett Avatar asked Apr 27 '13 00:04

Tom Crockett


1 Answers

Ok, this works:

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

scala> val unapply = unapplyMAB2[Monad, State, Int, Unit](IndexedStateT.stateMonad[Int])
unapply: scalaz.Unapply[scalaz.Monad,scalaz.State[Int,Unit]]{type M[X] = scalaz.State[Int,X]; type A = Unit} = scalaz.Unapply_0$$anon$13@53a6f572

scala> List(1, 2, 3).traverseU((i: Int) => unapply.TC.pure(i))
res0: scalaz.IndexedStateT[scalaz.Id.Id,Int,Int,List[Int]] = scalaz.IndexedStateT$$anon$10@737c45ee

In fact just regular old traverse works in this case:

scala> List(1, 2, 3).traverse((i: Int) => unapply.TC.pure(i))
res1: unapply.M[List[Int]] = scalaz.IndexedStateT$$anon$10@73c622ec

I suppose what's going on is that I need to have the Unapply instance in scope in order to know what types the TC field is referring to.

like image 91
Tom Crockett Avatar answered Oct 16 '22 05:10

Tom Crockett