Leibniz

sealed abstract
class Leibniz[-L, +H >: L, A >: L <: H, B >: L <: H]

Leibnizian equality: a better =:=

This technique was first used in Typing Dynamic Typing (Baars and Swierstra, ICFP 2002).

It is generalized here to handle subtyping so that it can be used with constrained type constructors.

Leibniz[L,H,A,B] says that A = B, and that both of its types are between L and H. Subtyping lets you loosen the bounds on L and H.

If you just need a witness that A = B, then you can use A===B which is a supertype of any Leibniz[L,H,A,B]

The more refined types are useful if you need to be able to substitute into restricted contexts.

Companion
object
class Object
trait Matchable
class Any

Value members

Abstract methods

def subst[F[_ >: L <: H]](p: F[A]): F[B]

Concrete methods

def andThen[L2 <: L, H2 >: H, C >: L2 <: H2](that: Leibniz[L2, H2, B, C]): Leibniz[L2, H2, A, C]
def apply(a: A): B
def compose[L2 <: L, H2 >: H, C >: L2 <: H2](that: Leibniz[L2, H2, C, A]): Leibniz[L2, H2, C, B]
def flip: Leibniz[L, H, B, A]
def liskov: Liskov[A, B]

A === B implies A <~< B.

A === B implies A <~< B.

def onContra[FA](fa: FA)(implicit U: AuxA[[F[_]] =>> Contravariant[F], FA, A]): M[B]
def onCov[FA](fa: FA)(implicit U: AuxA[[F[_]] =>> Functor[F], FA, A]): M[B]
def onF[X](fa: X => A): X => B