We are trying to fix that using HLists [1]. Unfortunately we didn't have
time yet to port our code to scalaz-seven, but I hope we will have
something by the end of this year.
Jason,I'm still going on with the migration of my app. to scalaz-seven and I found the following:- |> syntax is missing as I wrote before and I kinda like it in some cases
- ! syntax for State is missing
- I didn't see any Traverse instance for Seq
- there is a change in the State / StateT definition:def apply(initial: S): F[(A, S)]
I was used to S => (S, A). Maybe you wanted to make it closer to Haskell? I actually don't know why they choose this order in Haskell but I like the fact that State[S, A] and apply: S => (S, A) have their types in the same order. What is the reason for not doing that?
> `!` is so overloaded I would prefer to drop that method in favour of eval.
I think filterM will do what you want.
I agree that we should not flip the order unnecessarily, and it's
unfortunate that the order was "wrong" in 6. The are some (good?)
reasons why it should be (A, S):
1. The Kleisli arrow for State is
A => State[S, A]
A => S => (A, S) {expanded}
(A, S) => (A, S) {uncurried}
This way, Kleisli composition mirrors ordinary function composition in Endo.
2. State[S, _] is a composition of two functors: reader and writer.
type Reader[A] = S => A
type Writer[A] = (A, S)
Where Writer is left-adjunct to Reader. That way, the composition
Reader*Writer forms a monad: S => (A, S)
and the composition Writer*Reader forms a comonad: (S => A, S), so
that the implementations of unit and counit (for the monad and
comonad, respectively) are trivial:
def leftAdjunct[A, B](f: ((A, S)) => B): A => S => B =
Function.untupled(f).curried
def rightAdjunct[A, B](f: A => S => B): ((A, S)) => B =
Function.uncurried(f).tupled
def unit[A]: A => S => (A, S) = leftAdjunct(x => x)
def counit[A]: ((S => A, S)) => A = rightAdjunct(x => x)
I've also seen that you've added some specialized traverse functions, like "traverseS". I think that there's an issue with that because this creates a StackOverflow error on "big" streams. Could we instead provide a "trampolined version" for Stream by default?/** btw, traverseU works like magic! */def traverseState[S, B](f: A => State[S, B]) = seq.toStream.traverseU(f.trampolined).untrampolined
Now, here's quizz. I've defined the following function:def traverseStateIO[S, B](f: A => State[S, IO[B]])(init: S): Seq[B] = {implicit val applicative = StateTMApplicative[Trampoline, S, IO](seq.toStream.traverse[({type l[a]=StateT[Trampoline, S, IO[a]]})#l, B](f.trampolined).untrampolined eval init).unsafePerformIO}I've tried to generalize this to [M[_] : Applicative] instead of IO (then returning M[Seq[B]]). But I get compilation errors involving Id (how to do get a value out of Id? with Id.id.copoint?) and Unapply. Notably the compiler complains that M is invariant in Unapply. Do you think that this generalization is possible?/** it would be something like that*/def traverseStateM[M[_] : Applicative, S, B](f: A => State[S, M[B]])(init: S): M[Seq[B]] = {implicit val applicative = StateTMApplicative[Trampoline, S, M]Id.id.copoint(seq.toStream.traverse[({type l[a]=StateT[Trampoline, S, M[a]]})#l, B](f.trampolined).untrampolined eval init)}
Finally, I'm also wondering if we could define a trait UnapplyComposed like:trait UnapplyComposed[TC[_[_]], MA] {type M1[_]type M2[_]
type A/** The instance of the type class */def TC: TC[M1[M2[A]]/** Evidence that MA =:= M1[M2[A]] */def apply(ma: MA): M1[M2[A]]}and then in TraverseV:final def traverseComposed[GB](f: A => GB)(implicit G: Unapply[Applicative, GB]): G.M1[F[G.M2[G.A]]] = {G.TC.traverse(self)(a => G(f(a)))}
Oh yes, I forgot your question about the imports. I tried to stay with "import Scalaz._" and then restrict that if I had conflicts or add some missing imports (for syntax most notably)For example I wanted ?? on Boolean but ToAllV is missing an extension of ToBooleanV.
There is also a place where I'm using Monoids to fold a list of key K/values V, so that I get a list of key/(added values for the same key). I had to import:import std._import iterable._import map._
And also I found useful to define:def semigroupIsOptionMonoid[T : Semigroup] = new Monoid[Option[T]] {val zero: Option[T] = Nonedef append(t1: Option[T], t2 : =>Option[T]): Option[T] = (t1 <**> t2)(Semigroup[T].append(_, _))}That should totally make it to core (unless I missed it?)