PageRenderTime 40ms CodeModel.GetById 12ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 0ms

/core/src/main/scala/scalaz/Liskov.scala

http://github.com/scalaz/scalaz
Scala | 250 lines | 167 code | 46 blank | 37 comment | 0 complexity | 6b44c0fcbdde212eebd19c911576de6b MD5 | raw file
  1package scalaz
  2
  3/**
  4 * Liskov substitutability: A better `<:<`
  5 *
  6 * `A <: B` holds whenever `A` could be used in any negative context that expects a `B`.
  7 * (e.g. if you could pass an `A` into any function that expects a `B`.)
  8 */
  9sealed abstract class Liskov[-A, +B] {
 10  def apply(a: A): B = Liskov.witness(this)(a)
 11
 12  def substCo[F[+_]](p: F[A]): F[B]
 13  def substCt[F[-_]](p: F[B]): F[A]
 14
 15  final def *[x[+_, +_], C, D](that: Liskov[C, D]): Liskov[A x C, B x D] = Liskov.lift2(this, that)
 16
 17  final def andThen[C](that: Liskov[B, C]): Liskov[A, C] = Liskov.trans(that, this)
 18
 19  final def compose[C](that: Liskov[C, A]): Liskov[C, B] = Liskov.trans(this, that)
 20
 21  final def onF[X](fa: X => A): X => B = Liskov.co2_2[Function1, B, X, A](this)(fa)
 22}
 23
 24sealed abstract class LiskovInstances {
 25  import Liskov._
 26
 27  /** Subtyping forms a category */
 28  implicit val liskov: Category[<~<] = new Category[<~<] {
 29    def id[A]: (A <~< A) = refl[A]
 30
 31    def compose[A, B, C](bc: B <~< C, ab: A <~< B): (A <~< C) = trans(bc, ab)
 32  }
 33}
 34
 35object Liskov extends LiskovInstances {
 36
 37  /** A convenient type alias for Liskov */
 38  type <~<[-A, +B] = Liskov[A, B]
 39
 40  /** A flipped alias, for those used to their arrows running left to right */
 41  type >~>[+B, -A] = Liskov[A, B]
 42
 43  /** Lift Scala's subtyping relationship */
 44  implicit def isa[A, B >: A]: A <~< B = new (A <~< B) {
 45    def substCo[F[+ _]](p: F[A]) = p
 46    def substCt[F[- _]](p: F[B]) = p
 47  }
 48
 49  /** We can witness equality by using it to convert between types */
 50  implicit def witness[A, B](lt: A <~< B): A => B = {
 51    type f[-X] = X => B
 52    lt.substCt[f](identity)
 53  }
 54
 55  /** Subtyping is reflexive */
 56  implicit def refl[A]: (A <~< A) = new (A <~< A) {
 57    def substCo[F[+ _]](p: F[A]) = p
 58    def substCt[F[- _]](p: F[A]) = p
 59  }
 60
 61  private[scalaz] def fromLeibniz[A, B](ev: A === B): A <~< B =
 62    new (A <~< B) {
 63      def substCo[F[+ _]](p: F[A]) = ev.subst(p)
 64      def substCt[F[- _]](p: F[B]) = ev.flip.subst(p)
 65    }
 66
 67  /** Subtyping is transitive */
 68  def trans[A, B, C](f: B <~< C, g: A <~< B): A <~< C =
 69    g.substCt[λ[`-α` => α <~< C]](f)
 70
 71  /** We can lift subtyping into any covariant type constructor */
 72  def co[T[+_], A, A2](a: A <~< A2): (T[A] <~< T[A2]) =
 73    a.substCt[λ[`-α` => T[α] <~< T[A2]]](refl)
 74
 75  def co2[T[+_, _], Z, A, B](a: A <~< Z): T[A, B] <~< T[Z, B] =
 76    a.substCt[λ[`-α` => T[α, B] <~< T[Z, B]]](refl)
 77
 78  def co2_2[T[_, +_], Z, A, B](a: B <~< Z): T[A, B] <~< T[A, Z] =
 79    a.substCt[λ[`-α` => T[A, α] <~< T[A, Z]]](refl)
 80
 81  def co3[T[+_, _, _], Z, A, B, C](a: A <~< Z): T[A, B, C] <~< T[Z, B, C] =
 82    a.substCt[λ[`-α` => T[α, B, C] <~< T[Z, B, C]]](refl)
 83
 84  def co4[T[+_, _, _, _], Z, A, B, C, D](a: A <~< Z): T[A, B, C, D] <~< T[Z, B, C, D] =
 85    a.substCt[λ[`-α` => T[α, B, C, D] <~< T[Z, B, C, D]]](refl)
 86
 87  /** lift2(a,b) = co1_2(a) compose co2_2(b) */
 88  def lift2[T[+_, +_], A, A2, B, B2](
 89    a: A <~< A2,
 90    b: B <~< B2
 91  ): (T[A, B] <~< T[A2, B2]) = {
 92    type a[-X] = T[X, B2] <~< T[A2, B2]
 93    type b[-X] = T[A, X] <~< T[A2, B2]
 94    b.substCt[b](a.substCt[a](refl))
 95  }
 96
 97  /** lift3(a,b,c) = co1_3(a) compose co2_3(b) compose co3_3(c) */
 98  def lift3[T[+_, +_, +_], A, A2, B, B2, C, C2](
 99    a: A <~< A2,
100    b: B <~< B2,
101    c: C <~< C2
102  ): (T[A, B, C] <~< T[A2, B2, C2]) = {
103    type a[-X] = T[X, B2, C2] <~< T[A2, B2, C2]
104    type b[-X] = T[A, X, C2] <~< T[A2, B2, C2]
105    type c[-X] = T[A, B, X] <~< T[A2, B2, C2]
106    c.substCt[c](b.substCt[b](a.substCt[a](refl)))
107  }
108
109  /** lift4(a,b,c,d) = co1_3(a) compose co2_3(b) compose co3_3(c) compose co4_4(d) */
110  def lift4[T[+_, +_, +_, +_], A, A2, B, B2, C, C2, D, D2](
111    a: A <~< A2,
112    b: B <~< B2,
113    c: C <~< C2,
114    d: D <~< D2
115  ): (T[A, B, C, D] <~< T[A2, B2, C2, D2]) = {
116    type a[-X] = T[X, B2, C2, D2] <~< T[A2, B2, C2, D2]
117    type b[-X] = T[A, X, C2, D2] <~< T[A2, B2, C2, D2]
118    type c[-X] = T[A, B, X, D2] <~< T[A2, B2, C2, D2]
119    type d[-X] = T[A, B, C, X] <~< T[A2, B2, C2, D2]
120    d.substCt[d](c.substCt[c](b.substCt[b](a.substCt[a](refl))))
121  }
122
123  /** We can lift subtyping into any contravariant type constructor */
124  def contra[T[-_], A, A2](a: A <~< A2): (T[A2] <~< T[A]) =
125    a.substCt[λ[`-α` => T[A2] <~< T[α]]](refl)
126
127  // binary
128  def contra1_2[T[-_, _], Z, A, B](a: A <~< Z): (T[Z, B] <~< T[A, B]) =
129    a.substCt[λ[`-α` => T[Z, B] <~< T[α, B]]](refl)
130
131  def contra2_2[T[_, -_], Z, A, B](a: B <~< Z): (T[A, Z] <~< T[A, B]) =
132    a.substCt[λ[`-α` => T[A, Z] <~< T[A, α]]](refl)
133
134  // ternary
135  def contra1_3[T[-_, _, _], Z, A, B, C](a: A <~< Z): (T[Z, B, C] <~< T[A, B, C]) =
136    a.substCt[λ[`-α` => T[Z, B, C] <~< T[α, B, C]]](refl)
137
138  def contra2_3[T[_, -_, _], Z, A, B, C](a: B <~< Z): (T[A, Z, C] <~< T[A, B, C]) =
139    a.substCt[λ[`-α` => T[A, Z, C] <~< T[A, α, C]]](refl)
140
141  def contra3_3[T[_, _, -_], Z, A, B, C](a: C <~< Z): (T[A, B, Z] <~< T[A, B, C]) =
142    a.substCt[λ[`-α` => T[A, B, Z] <~< T[A, B, α]]](refl)
143
144  def contra1_4[T[-_, _, _, _], Z, A, B, C, D](a: A <~< Z): (T[Z, B, C, D] <~< T[A, B, C, D]) =
145    a.substCt[λ[`-α` => T[Z, B, C, D] <~< T[α, B, C, D]]](refl)
146
147  def contra2_4[T[_, -_, _, _], Z, A, B, C, D](a: B <~< Z): (T[A, Z, C, D] <~< T[A, B, C, D]) =
148    a.substCt[λ[`-α` => T[A, Z, C, D] <~< T[A, α, C, D]]](refl)
149
150  def contra3_4[T[_, _, -_, _], Z, A, B, C, D](a: C <~< Z): (T[A, B, Z, D] <~< T[A, B, C, D]) =
151    a.substCt[λ[`-α` => T[A, B, Z, D] <~< T[A, B, α, D]]](refl)
152
153  def contra4_4[T[_, _, _, -_], Z, A, B, C, D](a: D <~< Z): (T[A, B, C, Z] <~< T[A, B, C, D]) =
154    a.substCt[λ[`-α` => T[A, B, C, Z] <~< T[A, B, C, α]]](refl)
155
156  /** Lift subtyping into a unary function-like type
157   *  {{{
158   *      liftF1(a,r) = contra1_2(a) compose co2_2(b)
159   *  }}}
160   */
161  def liftF1[F[-_, +_], A, A2, R, R2](
162    a: A <~< A2,
163    r: R <~< R2
164  ): (F[A2, R] <~< F[A, R2]) = {
165    type a[-X] = F[A2, R2] <~< F[X, R2]
166    type r[-X] = F[A2, X] <~< F[A, R2]
167    r.substCt[r](a.substCt[a](refl))
168  }
169
170  /** Lift subtyping into a binary function-like type
171   *  {{{
172   *      liftF2(a,b,r) = contra1_3(a) compose contra2_3(b) compose co3_3(c)
173   *  }}}
174   */
175  def liftF2[F[-_, -_, +_], A, A2, B, B2, R, R2](
176    a: A <~< A2,
177    b: B <~< B2,
178    r: R <~< R2
179  ): (F[A2, B2, R] <~< F[A, B, R2]) = {
180    type a[-X] = F[A2, B2, R2] <~< F[X, B2, R2]
181    type b[-X] = F[A2, B2, R2] <~< F[A, X, R2]
182    type r[-X] = F[A2, B2, X] <~< F[A, B, R2]
183    r.substCt[r](b.substCt[b](a.substCt[a](refl)))
184  }
185
186  /** Lift subtyping into a ternary function-like type
187   *  {{{
188   *      liftF3(a,b,c,r) = contra1_4(a) compose contra2_4(b) compose contra3_4(c) compose co3_4(d)
189   *  }}}
190   */
191  def liftF3[F[-_, -_, -_, +_], A, A2, B, B2, C, C2, R, R2](
192     a: A <~< A2,
193     b: B <~< B2,
194     c: C <~< C2,
195     r: R <~< R2
196  ): (F[A2, B2, C2, R] <~< F[A, B, C, R2]) = {
197    type a[-X] = F[A2, B2, C2, R2] <~< F[X, B2, C2, R2]
198    type b[-X] = F[A2, B2, C2, R2] <~< F[A, X, C2, R2]
199    type c[-X] = F[A2, B2, C2, R2] <~< F[A, B, X, R2]
200    type r[-X] = F[A2, B2, C2, X] <~< F[A, B, C, R2]
201    r.substCt[r](c.substCt[c](b.substCt[b](a.substCt[a](refl))))
202  }
203
204  /** Lift subtyping into a 4-ary function-like type */
205  def liftF4[F[-_, -_, -_, -_, +_], A, A2, B, B2, C, C2, D, D2, R, R2](
206     a: A <~< A2,
207     b: B <~< B2,
208     c: C <~< C2,
209     d: D <~< D2,
210     r: R <~< R2
211   ): (F[A2, B2, C2, D2, R] <~< F[A, B, C, D, R2]) = {
212    type a[-X] = F[A2, B2, C2, D2, R2] <~< F[X, B2, C2, D2, R2]
213    type b[-X] = F[A2, B2, C2, D2, R2] <~< F[A, X, C2, D2, R2]
214    type c[-X] = F[A2, B2, C2, D2, R2] <~< F[A, B, X, D2, R2]
215    type d[-X] = F[A2, B2, C2, D2, R2] <~< F[A, B, C, X, R2]
216    type r[-X] = F[A2, B2, C2, D2, X] <~< F[A, B, C, D, R2]
217    r.substCt[r](d.substCt[d](c.substCt[c](b.substCt[b](a.substCt[a](refl)))))
218  }
219
220  /** Unsafely force a claim that A is a subtype of B. */
221  def force[A, B]: A <~< B =
222    new (A <~< B) {
223      def substCo[F[+ _]](p: F[A]) = p.asInstanceOf[F[B]]
224      def substCt[F[- _]](p: F[B]) = p.asInstanceOf[F[A]]
225    }
226
227  def unco[F[_] : Injective, Z, A](
228    a: F[A] <~< F[Z]
229  ): (A <~< Z) = force[A, Z]
230
231  def unco2_1[F[+_, _] : Injective2, Z, A, B](
232    a: F[A, B] <~< F[Z, B]
233  ): (A <~< Z) = force[A, Z]
234
235  def unco2_2[F[_, +_] : Injective2, Z, A, B](
236    a: F[A, B] <~< F[A, Z]
237  ): (B <~< Z) = force[B, Z]
238
239  def uncontra[F[-_] : Injective, Z, A](
240    a: F[A] <~< F[Z]
241  ): (Z <~< A) = force[Z, A]
242
243  def uncontra2_1[F[-_, _] : Injective2, Z, A, B](
244    a: F[A, B] <~< F[Z, B]
245  ): (Z <~< A) = force[Z, A]
246
247  def uncontra2_2[F[_, -_] : Injective2, Z, A, B](
248    a: F[A, B] <~< F[A, Z]
249  ): (Z <~< B) = force[Z, B]
250}