I'm using the Reader
monad in Scala as provided by the scalaz library. I'm familiar with this monad as defined in Haskell. The problem is that I cannot find the functions equivalent to return
, local
, and sequence
(among others).
Currently I use constructs that I do not like since I'm repeating myself or making my code a bit obscure.
Regarding return
, I'm currently using:
Reader{_ => someValue}
I'd rather just use a construct like unit(someValue)
, but I could not find anything on the internet. There are tutorials like this one that use the approach above, and which I consider not optimal.
Regarding local
I also have to do something similar: instead of typing something like: local f myReader
I have to unfold its definition:
Reader{env => myReader.run(f(env))
Finally, sequence is a bit closer to what I would expect (being a Haskell refugee doing Scala):
readers: List[Reader[Env, T]]
readerTs: Reader[Env, List[T]] = readers.sequenceU
My problem with this implementation is that, being relatively new to Scala, the type of sequenceU
final class TraverseOps[F[_],A] private[syntax](val self: F[A])(implicit val F: Traverse[F]) extends Ops[F[A]] {
//...
def sequenceU(implicit G: Unapply[Applicative, A]): G.M[F[G.A]]
appears like rather obscure, and seems like black magic. Ideally I would like to use a sequence
operations on Monads.
Is there a better translation of these constructs to Scala available on scalaz or similar library? I'm not married to any Functional library for Scala, so any solution using other libraries will do, although I'd rather have an answer using scalaz, since I already implemented my code using it.
To make the things simpler, I fill in some types. Changing them to defs with generic types should still work. Also I extracted the
ReaderInt
type, to avoid confusion with type lambdas.return / pure / point
Scala does not have automatic typeclass resolution, so you need to provide them implicitly. For
Kleisli
(being a monad transformer for reader),Kleisli[Id, ?, ?]
is enoughor with imported syntax:
So as a general rule, you
1) import the applicative intance, which usually located in
scalaz.std.something.somethingInstance
2)
import scalaz.syntax.something._
3) then you can write
x.point[F]
, whereF
is your applicative.local
Not sure, that it answers your question, but
Kleisli
has alocal
method.sequencing
The same way, you are free to choose to use
syntax
for or to specify type classes explicitly.I prefer not to use
sequenceU
, which usesUnapply
typelcass to infer theG
type, because sometimes scala has troubles of figuring out the right one. And I personally do not find it messy to put in some types myself.It may worth to look into cats, though it does not have much yet.