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's return
) or pure
(just a type alias) belongs to Applicative
trait. If you want to put something inside some F
, you need at least Applicative
instance for this F
.
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
implicit val KA = scalaz.Kleisli.kleisliIdApplicative[Int]
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
import scalaz.std.option.optionInstance
import scalaz.std.list.listInstance
etc...
Okay, you have the instance. Now you need to invoke point
on it.
You have few options:
1. Access method directly:
scalaz.std.option.optionInstance.point("hello")
KA.pure("hello")
2. Explicitly pull it from implicit context:
Applicative[Option].point("hello")
If you look into Applicative object, you would see
object Applicative {
@inline def apply[F[_]](implicit F: Applicative[F]): Applicative[F] = F
}
Implementation of apply
, is only returning the corresponding Applicative[F]
instance for some type F
.
So Applicative[Option].point("hello")
is converted to
Applicative[Option].apply(scalaz.std.option.optionInstance)
which in the end is just optionInstance
3. Use syntax
import scalaz.syntax.applicative._
brings this method into implicit scope:
implicit def ApplicativeIdV[A](v: => A) = new ApplicativeIdV[A] {
val nv = Need(v)
def self = nv.value
}
trait ApplicativeIdV[A] extends Ops[A] {
def point[F[_] : Applicative]: F[A] = Applicative[F].point(self)
def pure[F[_] : Applicative]: F[A] = Applicative[F].point(self)
def η[F[_] : Applicative]: F[A] = Applicative[F].point(self)
} ////
So then, whenever you try to invoke point
on a String
"hello".point[Option]
compiler realizes, that String
does not have the method point
and begins to look through implicits, how it can get something which has point
, from String
.
It finds, that it can convert String
to ApplicativeIdV[String]
, which indeed has method point
:
def point[F[_] : Applicative]: F[A] = Applicative[F].point(self)
So in the end - your call desugares to
new ApplicativeIdV[Option]("hello")
More or less all typeclasses in scalaz are working the same way.
For sequence
, the implementation is
def sequence[G[_]: Applicative, A](fga: F[G[A]]): G[F[A]] =
traverse(fga)(ga => ga)
This colon after G
means, that Applicative[G]
should be provided implicitly.
It is essentialy the same as:
def sequence[G[_], A](fga: F[G[A]])(implicit ev: Applicative[G[_]]): G[F[A]] =
traverse(fga)(ga => ga)
So all you need is the Applicative[G], and Traverse[F].
import scalaz.std.list.listInstance
import scalaz.std.option.optionInstance
Traverse[List].sequence[Option, String](Option("hello"))