/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

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