4

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.

Damian Nadales
  • 4,907
  • 1
  • 21
  • 34

1 Answers1

1

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 enough

 implicit val KA = scalaz.Kleisli.kleisliIdApplicative[Int]
 type ReaderInt[A] = Kleisli[Id.Id, Int, A]

 val alwaysHello = KA.point("hello")  

or with imported syntax:

  import scalaz.syntax.applicative._  
  val alwaysHello = "hello".point[ReaderInt]

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], where F is your applicative.

local

Not sure, that it answers your question, but Kleisli has a local method.

val f: String ⇒ Int = _.length
val alwaysEleven = alwaysHello local f

sequencing

The same way, you are free to choose to use syntax for or to specify type classes explicitly.

  import scalaz.std.list.listInstance
  val initial: List[ReaderInt[String]] = ???  
  val sequenced: ReaderInt[List[String]] = Traverse[List].sequence[ReaderInt, String](initial) 

  import scalaz.syntax.traverse._
  val z = x.sequence[ReaderInt, String]    

I prefer not to use sequenceU, which uses Unapply typelcass to infer the G 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.

I See Voices
  • 842
  • 5
  • 13
  • Thanks for the answer. I like the improvements in my code your suggestion brings. I just want to understand everything that is happening under the hood, but that will take some time I guess. – Damian Nadales Jul 27 '16 at 17:09
  • I'm amazed by how much accidental complexity I'm encountering to understand the implementation of a relatively simple concept such as the Reader Monad in Scala. http://stackoverflow.com/questions/38619516/scala-question-marks-in-type-parameters/38619906#38619906 – Damian Nadales Jul 27 '16 at 17:58
  • 1
    I agree that type lambdas (without kind projector) make code unnecessary convoluted. But the way you bring typeclasses and syntax in - is not so bad, especially when you get used to it. If you give me some time, I will update the answer, to clarify a bit what happens under the hood. – I See Voices Jul 27 '16 at 18:08
  • I really appreciate it. In the meantime I'm walking around the scalaz implementation. Quite lost though ... – Damian Nadales Jul 27 '16 at 18:56
  • I'm deriving some questions from your answer: http://stackoverflow.com/questions/38622081/scalaz-how-does-scalaz-syntax-applicative-works-its-magic – Damian Nadales Jul 27 '16 at 19:56