Un-boxed existential and universal quantifiers.
Exists[F[_]]
witnesses that there exists some typeA
and a value of typeF[A]
. For instance, if you want to witness that a some typeT
has an instance ofShow[T]
, you can provideExists[λ[α => (α, Show[α])]]
.Forall[F[_]]
is a universal quantification encoded as a type in Scala. If you want to witness that some typeF[_]
has a monoid instance regardless of the type argument, you can provideForall[λ[α => Monoid[F[α]]]]
.Instance[F[_]]
is a more convenient version ofExists[λ[α => (α, F[α])]]
that can be resolved implicitly (see example below).Sigma[A, F[_]]
is a dependent pair ofa: A
andF[a.type]
. You can useSigma.summon
to implicitly summon a proof for a given value:summon[λ[x => x <:< List[Int]]](Nil)
- isNil
together with a proof that it is a subtype ofList[Int]
.Pi[A, F[_]]
is a dependent function froma: A
toF[a.type]
.
resolvers += Resolver.bintrayRepo("alexknvl", "maven")
libraryDependencies += "com.alexknvl" %% "polymorphic" % "0.5.0"
// Currently available only for Scala 2.12 and 2.13
import polymorphic._
import std.data.quantified.syntax.all._
def bar(a: Instance[Show]*): String =
a.map(x => x.second.show(x.first)).mkString(", ")
bar(1, 2, 3) // "1, 2, 3"
class Foo[A]
val foo: ∀[Foo] = ∀(new Foo)
foo[Int] // : Foo[Int]
class Baz[A](val x: A) {
def show(a: A): String = a.toString
}
val baz: ∃[Baz] = ∃(new Baz(1))
baz.value.show(baz.value.x) // "1"
baz match { case Exists(f) => f.show(f.x) } // "1"
val optToList: Option ~> List = FunctionK(_.toList)
val listToOpt = FunctionK[List, Option](_.headOption)
Neither Exists
nor Forall
box their contents. Both are essentially opaque
newtypes over F[X]
:
type Exists[F[_]] <: Any { type T = A }
type Forall[F[_]] <: Any
Note that Forall[F]
is evaluated eagerly and only once. If you need a lazy
version of Forall
you might want to consider wrapping F
into cats.Eval
or
similar.
Code is provided under the MIT license available at https://opensource.org/licenses/MIT, as well as in the LICENSE file.