Skip to content
This repository was archived by the owner on Nov 29, 2020. It is now read-only.
This repository was archived by the owner on Nov 29, 2020. It is now read-only.

Sufficiency checker complains about a valid instance. #64

@sir-wabbit

Description

@sir-wabbit
import scalaz.meta.minimal

trait InvariantFunctor[F[_]] {
  def imap[A, B](ma: F[A])(f: A => B)(g: B => A): F[B]
}

trait Functor[F[_]] extends InvariantFunctor[F] {
  def map[A, B](ma: F[A])(f: A => B): F[B]

  def imap[A, B](ma: F[A])(f: A => B)(g: B => A): F[B] = map(ma)(f)
}

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

@minimal(("pure", "ap"), ("unit", "zip", "map"))
trait Applicative[F[_]] extends Apply[F] {
  def unit: F[Unit] = pure(())

  def pure[A](a: A): F[A] = map(unit)(_ => a)

  def zip[A, B](fa: F[A], fb: F[B]): F[(A, B)] = ap(fa)(map(fb)(b => a => (a, b)))

  def ap[A, B](fa: F[A])(f: F[A => B]): F[B] = map(zip(f, fa)) { case (f, a) => f(a) }

  def map[A, B](ma: F[A])(f: A => B): F[B] = ap(ma)(pure(f))
}

object ComposeImpl {
  type Compose[F[_], G[_]] = { type L[X] = F[G[X]] }

  def invariant[F[_], G[_]](implicit F0: InvariantFunctor[F], G0: InvariantFunctor[G]): InvariantFunctor[Compose[F, G]#L] =
    new ComposeInvariantFunctor[F, G] {
      val F = F0
      val G = G0
    }

  def functor[F[_], G[_]](implicit F0: Functor[F], G0: Functor[G]): Functor[Compose[F, G]#L] =
    new ComposeFunctor[F, G] {
      val F = F0
      val G = G0
    }

  def apply[F[_], G[_]](implicit F0: Apply[F], G0: Apply[G]): Apply[Compose[F, G]#L] =
    new ComposeApply[F, G] {
      val F = F0
      val G = G0
    }

  def applicative[F[_], G[_]](implicit F0: Applicative[F], G0: Applicative[G]): Applicative[Compose[F, G]#L] =
    new ComposeApplicative[F, G] {
      val F = F0
      val G = G0
    }

  private trait ComposeInvariantFunctor[F[_], G[_]] extends InvariantFunctor[Compose[F, G]#L] {
    val F: InvariantFunctor[F]
    val G: InvariantFunctor[G]

    final def imap[A, B](ma: F[G[A]])(f: A => B)(g: B => A): F[G[B]] =
      F.imap[G[A], G[B]](ma)(G.imap(_)(f)(g))(G.imap(_)(g)(f))
  }

  private trait ComposeFunctor[F[_], G[_]] extends Functor[Compose[F, G]#L] {
    val F: Functor[F]
    val G: Functor[G]

    final def map[A, B](fa: F[G[A]])(f: A => B): F[G[B]] =
      F.map(fa)(G.map(_)(f))
  }

  private trait ComposeApply[F[_], G[_]] extends ComposeFunctor[F, G] with Apply[Compose[F, G]#L] {
    val F: Apply[F]
    val G: Apply[G]

    final def ap[A, B](fa: F[G[A]])(f: F[G[A => B]]): F[G[B]] =
      F.ap(fa)(F.map(f)(gab => G.ap(_)(gab)))
  }

  private trait ComposeApplicative[F[_], G[_]] extends ComposeApply[F, G] with Applicative[Compose[F, G]#L] {
    val F: Applicative[F]
    val G: Applicative[G]

    final override def pure[A](a: A): F[G[A]] = F.pure(G.pure(a))
  }
}

Sufficiency checker complains missing implementation for methods: ap OR (unit AND zip AND map) on new ComposeApplicative[F, G].

Metadata

Metadata

Assignees

No one assigned

    Labels

    researchWe need to carefully think about this.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions