This question is related to this one, where I was trying to understand how to use the reader monad in Scala.
In the answer the autor uses the following code for getting an instance of ReaderInt[String]
:
import scalaz.syntax.applicative._
val alwaysHello2: ReaderInt[String] = "hello".point[ReaderInt]
Which mechanisms does Scala use to resolve the type of the expression "hello".point[ReaderInt]
so that it uses the right point
function?
I wanted to update the former answer, but since you created separate question, I put it here.
scalaz.syntax
Let's consider the
point
example, and you can apply the same reasoning for other methods.point
(or haskell'sreturn
) orpure
(just a type alias) belongs toApplicative
trait. If you want to put something inside someF
, you need at leastApplicative
instance for thisF
.Usually, you will provide it implicitly with imports, but you can specify it explicitly as well.
In example from the first question, I assigned it to
val
because scala was not able to figure out the corresponding
Int
type for this applicative. In other words, it did not know Applicative for which Reader to bring in. (though sometimes compiler can figure it out)For the Applicatives with one type parameter, we can bring implicit instances in just by using import
etc...
Okay, you have the instance. Now you need to invoke
point
on it. You have few options:1. Access method directly:
2. Explicitly pull it from implicit context:
If you look into Applicative object, you would see
Implementation of
apply
, is only returning the correspondingApplicative[F]
instance for some typeF
.So
Applicative[Option].point("hello")
is converted toApplicative[Option].apply(scalaz.std.option.optionInstance)
which in the end is justoptionInstance
3. Use syntax
brings this method into implicit scope:
So then, whenever you try to invoke
point
on aString
compiler realizes, that
String
does not have the methodpoint
and begins to look through implicits, how it can get something which haspoint
, fromString
.It finds, that it can convert
String
toApplicativeIdV[String]
, which indeed has methodpoint
:So in the end - your call desugares to
More or less all typeclasses in scalaz are working the same way. For
sequence
, the implementation isThis colon after
G
means, thatApplicative[G]
should be provided implicitly. It is essentialy the same as:So all you need is the Applicative[G], and Traverse[F].
A good first step any time you're trying to figure out something like this is to use the reflection API to desugar the expression:
(You generally don't want to use
scala.reflect.runtime
in real code, but it's extremely handy for investigations like this.)When the compiler sees you trying to call
.point[ReaderInt]
on a type that doesn't have apoint
method—in this caseString
—it starts looking for implicit conversions that would convert aString
into a type that does have a matchingpoint
method (this is called "enrichment" in Scala). We can see from the output ofshowCode
that the implicit conversion it finds is a method calledApplicativeIdV
in theapplicative
syntax object.It then applies this conversion to the
String
, resulting in a value of typeApplicativeIdV[String]
. This type'spoint
method looks like this:Which is syntactic sugar for something like this:
So the next thing it needs to do is find an
Applicative
instance forF
. In your case you've explicitly specified thatF
isReaderInt
. It resolves the alias toReader[Int, _]
, which is itself an alias forKleisli[Id.Id, Int, _]
, and starts looking for an instance.One of the first places it looks will be the
Kleisli
companion object, since it wants an implicit value of a type that includesKleisli
, and in factshowCode
tells us that the one it finds isKleisli.kleisliIdMonadReader
. At that point it's done, and we get theReaderInt[String]
we wanted.