Skip to content

Commit

Permalink
Type classes: expose super class functions in sub classes. (WIP)
Browse files Browse the repository at this point in the history
 Also ensure inheritance-based implementations via seal of type class.
 This avoid going through no-op invoke virtuals in most cases.

 WIP: Monoid/Semigroup/Functor->Monad only.
  • Loading branch information
jbgi committed Jan 21, 2018
1 parent c240494 commit 577fd61
Show file tree
Hide file tree
Showing 39 changed files with 282 additions and 265 deletions.
8 changes: 4 additions & 4 deletions base/shared/src/main/scala/scalaz/BaseHierarchy.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ object BaseHierarchy {
implicit def choiceProfunctor[P[_, _]](implicit P: Choice[P]): Profunctor[P] = P.profunctor
implicit def monadBind[M[_]](implicit M: Monad[M]): Bind[M] = M.bind
implicit def monadApplicative[M[_]](implicit M: Monad[M]): Applicative[M] = M.applicative
implicit def monadApply[M[_]](implicit M: Monad[M]): Apply[M] = M.applicative.apply
implicit def monadFunctor[M[_]](implicit M: Monad[M]): Functor[M] = M.applicative.apply.functor
implicit def monadApply[M[_]](implicit M: Monad[M]): Apply[M] = M.apply
implicit def monadFunctor[M[_]](implicit M: Monad[M]): Functor[M] = M.functor
implicit def monoidSemigroup[A](implicit A: Monoid[A]): Semigroup[A] = A.semigroup
implicit def traversableFoldable[T[_]](implicit T: Traversable[T]): Foldable[T] = T.foldable
implicit def categoryComposable[=>:[_,_]](implicit C: Category[=>:]): Compose[=>:] = C.compose
Expand All @@ -17,13 +17,13 @@ object BaseHierarchy {

trait BH1 extends BH2 {
implicit def bindApply[M[_]](implicit M: Bind[M]): Apply[M] = M.apply
implicit def bindFunctor[M[_]](implicit M: Bind[M]): Functor[M] = M.apply.functor
implicit def bindFunctor[M[_]](implicit M: Bind[M]): Functor[M] = M.functor
implicit def strongProfunctor[P[_, _]](implicit P: Strong[P]): Profunctor[P] = P.profunctor
}

trait BH2 extends BH3 {
implicit def applicativeApply[M[_]](implicit M: Applicative[M]): Apply[M] = M.apply
implicit def applicativeFunctor[M[_]](implicit M: Applicative[M]): Functor[M] = M.apply.functor
implicit def applicativeFunctor[M[_]](implicit M: Applicative[M]): Functor[M] = M.functor
}

trait BH3 extends BH4 {
Expand Down
19 changes: 10 additions & 9 deletions base/shared/src/main/scala/scalaz/Prelude.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,49 @@ package scalaz

trait BaseTypeclasses {
type Applicative[F[_]] = typeclass.Applicative[F]
val Applicative = typeclass.Applicative
type Apply[F[_]] = typeclass.Apply[F]
val Apply = typeclass.Apply
type Bind[M[_]] = typeclass.Bind[M]
val Bind = typeclass.Bind
type Category[=>:[_,_]] = typeclass.Category[=>:]
type Choice[P[_,_]] = typeclass.Choice[P]
type Cobind[F[_]] = typeclass.Cobind[F]
type Comonad[F[_]] = typeclass.Comonad[F]
type Compose[P[_,_]] = typeclass.Compose[P]
type Foldable[T[_]] = typeclass.Foldable[T]
val Foldable = typeclass.Foldable
type Functor[F[_]] = typeclass.Functor[F]
val Functor = typeclass.Functor
type InvariantFunctor[F[_]] = typeclass.InvariantFunctor[F]
type IsContravariant[F[_]] = typeclass.IsContravariant[F]
type IsCovariant[F[_]] = typeclass.IsCovariant[F]
type Monad[M[_]] = typeclass.Monad[M]
val Monad = typeclass.Monad
type Monoid[T] = typeclass.Monoid[T]
val Monoid = typeclass.Monoid
type Phantom[F[_]] = typeclass.Phantom[F]
type Profunctor[F[_,_]] = typeclass.Profunctor[F]
type Semigroup[T] = typeclass.Semigroup[T]
val Semigroup = typeclass.Semigroup
type Show[A] = typeclass.Show[A]
type Strong[F[_,_]] = typeclass.Strong[F]
type Traversable[T[_]] = typeclass.Traversable[T]
val Traversable = typeclass.Traversable


def Applicative[F[_]](implicit F: Applicative[F]): Applicative[F] = F
def Apply[F[_]](implicit F: Apply[F]): Apply[F] = F
def Bind[F[_]](implicit F: Bind[F]): Bind[F] = F
def Category[=>:[_,_]](implicit P: Category[=>:]): Category[=>:] = P
def Choice[P[_,_]](implicit P: Choice[P]): Choice[P] = P
def Cobind[F[_]](implicit F: Cobind[F]): Cobind[F] = F
def Comonad[F[_]](implicit F: Comonad[F]): Comonad[F] = F
def Compose[P[_,_]](implicit P: Compose[P]): Compose[P] = P
def Foldable[F[_]](implicit F: Foldable[F]): Foldable[F] = F
def Functor[F[_]](implicit F: Functor[F]): Functor[F] = F
def InvariantFunctor[F[_]](implicit F: InvariantFunctor[F]): InvariantFunctor[F] = F
def IsContravariant[F[_]](implicit F: IsContravariant[F]): IsContravariant[F] = F
def IsCovariant[F[_]](implicit F: IsCovariant[F]): IsCovariant[F] = F
def Monad[M[_]](implicit M: Monad[M]): Monad[M] = M
def Monoid[T](implicit T: Monoid[T]): Monoid[T] = T
def Phantom[F[_]](implicit F: Phantom[F]): Phantom[F] = F
def Profunctor[P[_,_]](implicit P: Profunctor[P]): Profunctor[P] = P
def Semigroup[T](implicit T: Semigroup[T]): Semigroup[T] = T
def Show[A](implicit A: Show[A]): Show[A] = A
def Strong[P[_,_]](implicit P: Strong[P]): Strong[P] = P
def Traversable[T[_]](implicit T: Traversable[T]): Traversable[T] = T
}

trait BaseData {
Expand Down
57 changes: 34 additions & 23 deletions base/shared/src/main/scala/scalaz/data/ConstInstances.scala
Original file line number Diff line number Diff line change
@@ -1,50 +1,61 @@
package scalaz
package data

import typeclass.{FoldableClass, TraversableClass}

import Prelude._
import FoldableClass._
import TraversableClass._

trait ConstInstances {
implicit def constTraverse[R]: Traversable[Const[R, ?]] = new TraversableClass[Const[R, ?]] with FoldRight[Const[R, ?]] with Traverse[Const[R, ?]] {
def map[A, B](ma: Const[R, A])(f: A => B): Const[R, B] = ma.retag
implicit def constTraverse[R]: Traversable[Const[R, ?]] = new Traversable.Template[Const[R, ?]] with Traversable.DeriveSequence[Const[R, ?]] with Foldable.DeriveFoldMap[Const[R, ?]] with ConstFunctor[R] {

def traverse[F[_], A, B](ta: Const[R, A])(f: A => F[B])(implicit F: Applicative[F]): F[Const[R, B]] =
override def traverse[F[_], A, B](ta: Const[R, A])(f: A => F[B])(implicit F: Applicative[F]): F[Const[R, B]] =
F.pure(ta.retag)

def foldLeft[A, B](fa: Const[R, A], z: B)(f: (B, A) => B): B = z
override def foldLeft[A, B](fa: Const[R, A], z: B)(f: (B, A) => B): B = z

def foldRight[A, B](fa: Const[R, A], z: => B)(f: (A, => B) => B): B = z
override def foldRight[A, B](fa: Const[R, A], z: => B)(f: (A, => B) => B): B = z

override def toList[A](fa: Const[R, A]): List[A] = Nil
}

implicit def constFunctor[R]: Functor[Const[R, ?]] = new Functor[Const[R, ?]] {
def map[A, B](fa: Const[R, A])(f: A => B): Const[R, B] =
private trait ConstFunctor[R] extends Functor.Template[Const[R, ?]] {
final override def map[A, B](fa: Const[R, A])(f: A => B): Const[R, B] =
fa.retag[B]
}

implicit def constApply[R](implicit R: Semigroup[R]): Apply[Const[R, ?]] = new Apply[Const[R, ?]] {
def functor: Functor[Const[R, ?]] = Const.constFunctor[R]
def ap[A, B](fa: Const[R, A])(f: Const[R, A => B]): Const[R, B] =
private trait ConstApply[R] extends Apply.Template[Const[R, ?]] with ConstFunctor[R] {
def R: Semigroup.Class[R]
final override def ap[A, B](fa: Const[R, A])(f: Const[R, A => B]): Const[R, B] =
Const(R.append(fa.getConst, f.getConst))
}

implicit def constApplicative[R](implicit R: Monoid[R]): Applicative[Const[R, ?]] = new Applicative[Const[R, ?]] {
def apply: Apply[Const[R, ?]] = Const.constApply[R]
def pure[A](a: A): Const[R, A] = Const(R.empty)
private trait ConstApplicative[R] extends Applicative.Template[Const[R, ?]] with ConstApply[R] {
override def R: Monoid.Class[R]
final override def pure[A](a: A): Const[R, A] = Const(R.empty)
}

implicit def constSemigroup[A, B](implicit A: Semigroup[A]): Semigroup[Const[A, B]] = new Semigroup[Const[A, B]] {
def append(a1: Const[A, B], a2: => Const[A, B]): Const[A, B] =
private trait ConstSemigroup[A, B] extends Semigroup.Template[Const[A, B]] {
def A: Semigroup.Class[A]
final override def append(a1: Const[A, B], a2: => Const[A, B]): Const[A, B] =
Const(A.append(a1.getConst, a2.getConst))
}

implicit def constMonoid[A, B](implicit A: Monoid[A]): Monoid[Const[A, B]] = new Monoid[Const[A, B]] {
def semigroup: Semigroup[Const[A, B]] = implicitly
def empty: Const[A, B] = Const(A.empty)
private trait ConstMonoid[A, B] extends Monoid.Template[Const[A, B]] with ConstSemigroup[A, B] {
override def A: Monoid.Class[A]
final override def empty: Const[A, B] = Const(A.empty)
}

implicit def constApply[R: Semigroup]: Apply[Const[R, ?]] = new ConstApply[R] {
override val R = implicitly
}

implicit def constApplicative[R: Monoid]: Applicative[Const[R, ?]] = new ConstApplicative[R] {
override val R = implicitly
}

implicit def constSemigroup[A: Semigroup, B]: Semigroup[Const[A, B]] = new ConstSemigroup[A, B] {
override val A = implicitly
}

implicit def constMonoid[A: Monoid, B]: Monoid[Const[A, B]] = new ConstMonoid[A, B] {
override val A = implicitly
}

implicit def constShow[A, B](implicit A: Show[A]): Show[Const[A, B]] =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package scalaz
package data

import typeclass.MonadClass

trait DisjunctionInstances {
implicit def disjunctionMonad[L]: Monad[L \/ ?] = new MonadClass.Template[L \/ ?] {
implicit def disjunctionMonad[L]: Monad[L \/ ?] = new Monad.Template[L \/ ?] with Bind.DeriveFlatten[L \/ ?] {

override def map[A, B](ma: L \/ A)(f: A => B): L \/ B =
ma.fold[L \/ B](l => -\/(l))(r => \/-(f(r)))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package scalaz
package data

import typeclass.MonadClass

trait IdentityInstances {
implicit val monad: Monad[Identity] = new MonadClass[Identity] {
implicit val monad: Monad[Identity] = new Monad.Template[Identity] {
override def map[A, B](fa: Identity[A])(f: A => B): Identity[B] = Identity(f(fa.run))
override def ap[A, B](fa: Identity[A])(f: Identity[A => B]): Identity[B] = Identity(f.run.apply(fa.run))
override def ap[A, B](fa: Identity[A])(f: Identity[A => B]): Identity[B] = Identity(f.run(fa.run))
override def pure[A](a: A): Identity[A] = Identity(a)
override def flatMap[A, B](oa: Identity[A])(f: A => Identity[B]): Identity[B] = f(oa.run)
override def flatten[A](ma: Identity[Identity[A]]): Identity[A] = ma.run
Expand Down
9 changes: 3 additions & 6 deletions base/shared/src/main/scala/scalaz/data/Maybe.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package scalaz
package data

import typeclass.{MonadClass, TraversableClass}
import typeclass.FoldableClass._

sealed trait MaybeModule {
type Maybe[A]

Expand Down Expand Up @@ -60,7 +57,7 @@ private[scalaz] object MaybeImpl extends MaybeModule {
}

private val instance =
new MonadClass.Template[Maybe] with TraversableClass[Maybe] with FoldRight[Maybe] {
new Monad.Template[Maybe] with Bind.DeriveFlatten[Maybe] with Traversable.Template[Maybe] with Foldable.DeriveFoldMap[Maybe] {

override def ap[A, B](ma: Maybe[A])(mf: Maybe[A => B]): Maybe[B] =
mf match {
Expand All @@ -79,13 +76,13 @@ private[scalaz] object MaybeImpl extends MaybeModule {

override def traverse[F[_], A, B](ma: Maybe[A])(f: A => F[B])(implicit F: Applicative[F]): F[Maybe[B]] =
ma match {
case Some(a) => F.apply.functor.map(f(a))(just)
case Some(a) => F.map(f(a))(just)
case None => F.pure(None)
}

override def sequence[F[_], A](ma: Maybe[F[A]])(implicit F: Applicative[F]): F[Maybe[A]] =
ma match {
case Some(fa) => F.apply.functor.map(fa)(just)
case Some(fa) => F.map(fa)(just)
case None => F.pure(None)
}

Expand Down
4 changes: 2 additions & 2 deletions base/shared/src/main/scala/scalaz/data/These.scala
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ sealed abstract class These[L, R] {
/* Traversable (on the right) */
final def traverse[F[_], B](f: R => F[B])(implicit F: Applicative[F]): F[These[L, B]] = this match {
case thiz @ This(_) => F.pure(thiz.pmap[B])
case That(right) => F.apply.functor.map(f(right))(That(_))
case Both(left, right) => F.apply.functor.map(f(right))(Both(left, _))
case That(right) => F.map(f(right))(That(_))
case Both(left, right) => F.map(f(right))(Both(left, _))
}

/* Semigroup */
Expand Down
11 changes: 4 additions & 7 deletions base/shared/src/main/scala/scalaz/data/TheseInstances.scala
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
package scalaz
package data

import typeclass.{ BindClass, FoldableClass, MonadClass, SemigroupClass, TraversableClass }

trait TheseInstances {
// implicit def bifunctor: Bifunctor[These] = ...

implicit final def theseMonad[L: Semigroup]: Monad[These[L, ?]] =
new MonadClass.Template[These[L, ?]] with BindClass.Ap[These[L, ?]] {
new Monad.Template[These[L, ?]] with Bind.DeriveAp[These[L, ?]] with Bind.DeriveFlatten[These[L, ?]] {
override def map[A, B](ma: These[L, A])(f: A => B) = ma.rmap(f)
def flatMap[A, B](ma: These[L, A])(f: A => These[L, B]) = ma.flatMap(f)
def pure[A](a: A) = That(a)
}

implicit final def theseTraversable[L]: Traversable[These[L, ?]] =
new TraversableClass[These[L, ?]]
with TraversableClass.Traverse[These[L, ?]]
with FoldableClass.FoldMap[These[L, ?]] {
new Traversable.Template[These[L, ?]]
with Traversable.DeriveSequence[These[L, ?]] with Foldable.DeriveToList[These[L, ?]] {
def traverse[F[_]: Applicative, A, B](ta: These[L, A])(f: A => F[B]) = ta.traverse(f)
def foldMap[A, B: Monoid](fa: These[L, A])(f: A => B) = fa.foldMap(f)
def map[A, B](ma: These[L, A])(f: A => B) = ma.rmap(f)
Expand All @@ -27,7 +24,7 @@ trait TheseInstances {
}

implicit final def theseSemigroup[L: Semigroup, R: Semigroup]: Semigroup[These[L, R]] =
new SemigroupClass[These[L, R]] {
new Semigroup.Template[These[L, R]] {
def append(a1: These[L, R], a2: => These[L, R]) = a1.append(a2)
}

Expand Down
24 changes: 20 additions & 4 deletions base/shared/src/main/scala/scalaz/typeclass/Applicative.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
package scalaz
package typeclass

trait Applicative[F[_]] {
def apply: Apply[F]
def pure[A](a: A): F[A]
}
sealed trait Applicative[F[_]] extends Applicative.Class[F]

object Applicative {

trait Class[F[_]] extends Apply.Class[F] {
def pure[A](a: A): F[A]

def applicative: Applicative[F]
}

trait Template[F[_]] extends Apply.Template[F] with Applicative[F] {
final override def applicative = this
}

trait DeriveMap[F[_]] extends Monad.Alt[DeriveMap[F]] { self: Class[F] =>
final override def map[A, B](ma: F[A])(f: (A) => B): F[B] = ap(ma)(pure(f))
}

def apply[F[_]](implicit F: Applicative[F]): Applicative[F] = F
}
14 changes: 0 additions & 14 deletions base/shared/src/main/scala/scalaz/typeclass/ApplicativeClass.scala

This file was deleted.

20 changes: 16 additions & 4 deletions base/shared/src/main/scala/scalaz/typeclass/Apply.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
package scalaz
package typeclass

trait Apply[F[_]] {
def functor: Functor[F]
def ap[A, B](fa: F[A])(f: F[A => B]): F[B]
}
sealed trait Apply[F[_]] extends Apply.Class[F]

object Apply {

trait Class[F[_]] extends Functor.Class[F] {
def ap[A, B](fa: F[A])(f: F[A => B]): F[B]

def apply: Apply[F]
}

trait Template[F[_]] extends Functor.Template[F] with Apply[F] {
final override def apply = this
}

def apply[F[_]](implicit F: Apply[F]): Apply[F] = F
}
6 changes: 0 additions & 6 deletions base/shared/src/main/scala/scalaz/typeclass/ApplyClass.scala

This file was deleted.

34 changes: 29 additions & 5 deletions base/shared/src/main/scala/scalaz/typeclass/Bind.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
package scalaz
package typeclass

trait Bind[M[_]] {
def apply: Apply[M]
def flatMap[A, B](ma: M[A])(f: A => M[B]): M[B]
def flatten[A](ma: M[M[A]]): M[A]
}
sealed trait Bind[M[_]] extends Bind.Class[M]

object Bind {

trait Class[M[_]] extends Apply.Class[M] {
def flatMap[A, B](ma: M[A])(f: A => M[B]): M[B]
def flatten[A](ma: M[M[A]]): M[A]

def bind: Bind[M]
}

trait Template[M[_]] extends Apply.Template[M] with Bind[M] {
final override def bind = this
}

trait DeriveAp[M[_]] extends Monad.Alt[DeriveAp[M]] { self: Class[M] =>
final override def ap[A, B](fa: M[A])(f: M[A => B]): M[B] = flatMap(f)(map(fa))
}

trait Alt[D <: Alt[D]]
trait DeriveFlatten[M[_]] extends Alt[DeriveFlatten[M]] { self: Class[M] =>
final override def flatten[A](ma: M[M[A]]): M[A] = flatMap(ma)(identity)
}
trait DeriveFlatMap[M[_]] extends Alt[DeriveFlatMap[M]] { self: Class[M] =>
final override def flatMap[A, B](ma: M[A])(f: (A) => M[B]): M[B] = flatten(map(ma)(f))
}

def apply[F[_]](implicit F: Bind[F]): Bind[F] = F
}
Loading

0 comments on commit 577fd61

Please sign in to comment.