设为首页 加入收藏

TOP

Scalaz(27)- Inference & Unapply :类型的推导和匹配(一)
2017-10-10 12:13:20 】 浏览:1155
Tags:Scalaz Inference Unapply 类型 推导 匹配

  经过一段时间的摸索,用scala进行函数式编程的过程对我来说就好像是想着法儿如何将函数的款式对齐以及如何正确地匹配类型,真正是一种全新的体验,但好像有点太偏重学术型了。 本来不想花什么功夫在scala的类型系统上,但在阅读scalaz源代码时往往遇到类型层面的编程(type level programming),常常扰乱了理解scalaz代码思路,所以还是要简单的介绍一下scala类型系统的一些情况。scala类型系统在scala语言教材中一般都提及到了。但有些特殊的类型如phantom type, dependent type等,以及在一些场合下使用类型的特殊技巧还是值得研究的。scala类型系统的主要功能就是在程序运行之前,在编译时(compile time)尽量捕捉代码中可能出现的错误,也就是类型不匹配错误。scala类型系统是通过找寻隐式转换类型证例(implicit type evidence)来判断代码中当前类型是否期待的类型从而确定是否发生类型错误(type error)。写起来很简单,我们只要用隐式参数(implicit parameter)来表述一个隐式的类型实例(implicit type instance):

1 trait Proof 2 def sayHi(implicit isthere: Proof) = println("hello") 3 sayHi    //编译失败

创建一个Proof实例后:

1 trait Proof 2 def sayHi(implicit isthere: Proof) = println("hello") 3                                                   //> sayHi: (implicit isthere: Exercises.deptype.Proof)Unit
4 implicit object ishere extends Proof  //建一个实例
5 sayHi                                             //> hello

sayHi现在能正常通过编译了。虽然在sayHi函数内部并没有引用这个隐式参数isthere,但这个例子可以说明编译器进行类型推断的原理。一般来说我们都会在函数内部引用isthere这种隐式参数,并且按不同需要在隐式转换解析域内创建不同功能的类型实例(instance):

1 trait Proof { def apply(): String} 2 def sayHi(implicit isthere: Proof) = println(isthere()) 3                                                   //> sayHi: (implicit isthere: Exercises.deptype.Proof)Unit
4 implicit object ishere extends Proof {def apply() = "Hello World!"} 5 sayHi                                             //> Hello World!

在Scalaz中还有些更复杂的引用例子如:scalaz/BindSyntax.scala

def join[B](implicit ev: A <~< F[B]): F[B] = F.bind(self)(ev(_))
1  List(List(1),List(2),List(3)).join                //> res0: List[Int] = List(1, 2, 3) 2 //List(1.some,2.some,3.some).join //无法编译,输入类型不对

以上例子里的隐式转换和解析域就比较隐晦了:scalaz/Liskov.Scala

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 }

这个隐式转换产生的实例限定了A必须是B或者是B的子类。在这个例子中不但限定了类型的正确性,而且还进行了些类型关系的推导。理论上我们可以用依赖类型(dependent type)来描述类型参数之间的关系,推导结果类型最终确定代码中类型的正确无误。据我所知scala并不支持完整功能的依赖类型,但有些前辈在scala类型编程(type level programming)中使用了一些依赖类型的功能和技巧。Scalaz的unapply就利用了依赖类型的原理,然后通过隐式参数(implicit parameter)证明某些类型实例的存在来判断输入参数类型正确性的。Unapply的构思是由Miles Sabin创造的。我们先用他举的一个例子来看看如何利用依赖类型及类型实例通过隐式输入参数类型来推导结果类型并判断输入参数类型正确性的:

 1 trait TypeA  2 trait TypeB  3 
 4 trait DepType[A,B,C]  //依赖类型
 5 implicit object abb extends DepType[TypeA,TypeB,TypeB] {  6     def apply(a:TypeA, b:TypeB): TypeB = error("TODO")  //结果类型依赖TypeA和TypeB
 7 }  8 implicit object aaa extends DepType[TypeA,TypeA,TypeA] {  9     def apply(a:TypeA, b:TypeA): TypeA = error("TODO")  //结果类型依赖TypeA和TypeA
10 } 11 implicit object iab extends DepType[Int,TypeA,TypeB] { 12     def apply(a:Int, b:TypeA): TypeB = error("TODO")  //结果类型依赖Int和TypeB
13 } 14 implicit object bbi extends DepType[TypeB, TypeB, Int] { 15     def apply(a:TypeB, b:TypeB): Int = error("TODO")  //结果类型依赖Int和TypeB
16 } 17 implicitly[DepType[Int,TypeA,TypeB]]              //> res1: Exercises.deptype.DepType[Int,Exercises.deptype.TypeA,Exercises.deptyp 18                                                   //| e.TypeB] = Exercises.deptype$$anonfun$main$1$iab$2$@7722c3c3
19 implicitly[DepType[TypeB,TypeB,Int]]              //> res2: Exercises.deptype.DepType[Exercises.deptype.TypeB,Exercises.deptype.Ty 20                                                   //| peB,Int] = Exercises.deptype$$anonfun$main$1$bbi$2$@2ef3eef9
21 
22 implicitly[DepType[TypeA,TypeB,TypeB]]            //> res3: Exercises.deptype.DepTyp
首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Scalaz(25)- Monad: Monad Tr.. 下一篇Scala简单计算实例,其在数据分析..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目