lundi 11 juin 2018

Scalaz, the purpose of *syntax classes

In scalaz when we define a module, we additionally define implicit, helper functions. Here is an example of definition and how it could be used by a client:

trait Functor[F[_]] {
  def map[A,B](fa: F[A])(f: A => B): F[B]
}
object Functor {
  def fmap[F[_], A,B](as:F[A])(f:A=>B)
                    (implicit ff:Functor[F]):F[B] =
    ff.map(as)(f)

  implicit val listFunctor = new Functor[List] {
    def map[A,B](as: List[A])(f: A => B): List[B] = as map f
  }
}
...
import com.savdev.NewLibrary._
val r = fmap(List(1,2))(_.toString)

final class FunctorOps[F[_], A](self: F[A])(implicit ff:Functor[F]){
  def qmap[B](f:A=>B):F[B] = ff.map(self)(f)
}
trait FunctorSyntax {
  implicit def ToFunctorOps[F[_],A](v: F[A])(implicit F0: Functor[F]) =
    new FunctorOps[F,A](v)
}
object NewLibrary extends FunctorSyntax
...
import com.savdev.NewLibrary._
val r = fmap(List(1,2))(_.toString)

The code is slightly changed. But the idea is that we define:

  1. An abstraction and its API (algebra)
  2. Define helper generic functions that use implicits and implicits themselves
  3. Enrich existing types to be able to use our new abstraction. Implicit convertion is used for that. In scalaz we define a final class for a wrapper and implicit converters in traits

All above, the motivation of it and how it can be used by a client is clear. But in to each such module definition, there is also a related *Syntax class. I cannot understand the purpose of it. Can you please exlain, why it is needed and HOW it can be used in a client code.

Aucun commentaire:

Enregistrer un commentaire