设为首页 加入收藏

TOP

Scalaz(21)-类型例证:Liskov and Leibniz - type evidence(二)
2017-10-10 12:13:26 】 浏览:4424
Tags:Scalaz 类型 例证 Liskov and Leibniz type evidence
[L,H,A,B]`
*/ type ===[A,B] = Leibniz[⊥, ?, A, B] } 和 trait LeibnizFunctions { import Leibniz._ /** Equality is reflexive -- we rely on subtyping to expand this type */ implicit def refl[A]: Leibniz[A, A, A, A] = new Leibniz[A, A, A, A] { def subst[F[_ >: A <: A]](p: F[A]): F[A] = p } /** We can witness equality by using it to convert between types * We rely on subtyping to enable this to work for any Leibniz arrow */ implicit def witness[A, B](f: A === B): A => B = f.subst[({type λ[X] = A => X})#λ](identity) implicit def subst[A, B](a: A)(implicit f: A === B): B = f.subst[Id](a) ...

当我们尝试找寻Leibniz[A,String]实例时唯一可能就只有Leibniz[A,A,A,A],类型转换其实就是通过把subst的传入参数转变成返回结果。我们可以用下面的方法证明:

implicitly[Int === Int]     //> res2: scalaz.Leibniz.===[Int,Int] = scalaz.LeibnizFunctions$$anon$2@9f70c54
implicitly[String === Int]  //could not find implicit value for parameter e: scalaz.Leibniz.===[String,Int]

ev(a)就是apply(a)=subst[Id](a)=a, 暗地里subst帮助了类型转换A=>String,这点我们可以通过调换A和String的位置来再次证明:

  def getLength(implicit ev: String === A): Int = ev(a).length  //type mismatch; found : A required: String

同样的我们可以看看Liskov定义:scalaz/Liskov.scala

sealed abstract class Liskov[-A, +B] { def apply(a: A): B = Liskov.witness(this)(a) def subst[F[-_]](p: F[B]): F[A] ...

同样是这个subst函数:首先F[-_]是逆变,F[B]=>F[A]需要A是B的子类。隐式转换解析:

object Liskov extends LiskovInstances with LiskovFunctions { /**A convenient type alias for Liskov */ type <~<[-A, +B] = Liskov[A, B] /**A flipped alias, for those used to their arrows running left to right */ type >~>[+B, -A] = Liskov[A, B] } 和 trait LiskovFunctions { import Liskov._ /**Lift Scala's subtyping relationship */
  implicit def isa[A, B >: A]: A <~< B = new (A <~< B) { def subst[F[-_]](p: F[B]): F[A] = p } /**We can witness equality by using it to convert between types */
  implicit def witness[A, B](lt: A <~< B): A => B = { type f[-X] = X => B lt.subst[f](identity) } /**Subtyping is reflexive */
  implicit def refl[A]: (A <~< A) = new (A <~< A) { def subst[F[-_]](p: F[A]): F[A] = p } ...

我们可以看到在 A <~< B 实例的类型转换函数subst中输入参数F[B]直接替代返回结果F[A],因为F[]是逆变(contravariant)而A是B的子类。也就是我们可以用A替代B。

好,我们试试分析上面提到的join函数。众所周知,join函数是Monad的打平函数(flaten function)。这个版本可以在这里找到:scalaz/Bind.scala

  /** Sequence the inner `F` of `FFA` after the outer `F`, forming a * single `F[A]`. */ def join[A](ffa: F[F[A]]) = bind(ffa)(a => a)

这个容易理解。但我们现在面对的是这个版本:scalaz/BindSyntax.scala

 def join[B](implicit ev: A <~< F[B]): F[B] = F.bind(self)(ev(_))

这里使用了Leskov,我们看看到底发生了什么:

List(List(1),List(2),List(3)).join       //> res3: List[Int] = List(1, 2, 3)
List(1.some,2.some,3.some).join          //could not find implicit value for parameter ev: scalaz.Liskov.<~<[Option[Int],List[B]]

正确的ev实例需要Liskov[List[List[Int]],List[Int]],List[List[Int]]是List[Int]的子类。在subst函数里输入参数F[B]直接替代了返回结果F[A]。那么:

 F.bind(List[List[A]])(ev(List[A]))

=F.bind(List[List[A]])(witness(Leskov[List[List[Int]],List[Int]])(List[List[Int]])

=F.bind(List[List[A]])(List[Int])

=List[Int]

我们看到List[List[Int]]被witness转换成List[Int]。

上面的分析好像很神奇,但我们隐约可以感受到scala类型系统的强大推断能力。通过提供一些类型的实例,它为我们产生了许多源代码。

 

 

 

 

 

 

 

首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Scalaz(20)-Monad: Validatio.. 下一篇Scalaz(22)- 泛函编程思维: C..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目