前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Scala的类型推断

Scala的类型推断

作者头像
哒呵呵
发布2018-08-06 14:11:55
6190
发布2018-08-06 14:11:55
举报
文章被收录于专栏:鸿的学习笔记

从一段代码开始:

代码语言:javascript
复制
scala> def sort1[T](cp:(T,T) => Boolean)(xs:List[T]) = {xs sortWith (cp)}
sort1: [T](cp: (T, T) => Boolean)(xs: List[T])List[T]

scala> sort1((x:Int,y:Int)=>x>y)(List(1,2,3,4,5))
res0: List[Int] = List(5, 4, 3, 2, 1)

scala> List(1,2,3,4,5) sortWith (_>_)
res1: List[Int] = List(5, 4, 3, 2, 1)

scala> sort1(_>_)(List(1,2,3,4,5))
<console>:9: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$greater(x$2))
              sort1(_>_)(List(1,2,3,4,5))

上面的两端代码都是等价的,但是第一段代码sort1这个偏函数需要指定传入的类型才能运行,而sortWith则不需要。对于等效的代码,为什么sort1无法使用类型推断,而sortWith可以呢?

首先看看维基上对类型推断的定义:

Type inference refers to the automatic detection of the data type of an expression in a programming language.

类型推断指的是程序语言有自动推断表达式数据类型的能力,而无需程序员指定数据类型,简化程序员的工作。如下面,可以指定a为Int类型,也可以让Scala推断出b为Int类型。

代码语言:javascript
复制
scala> val a:Int = 1
a: Int = 1

scala> val b = 1
b: Int = 1

对于类型推断算法最出名的应该是HM算法,大概意思就是先构建一棵包含全部元素的解析树,再分析全部元素可能属于的类型,并且达到推导出最终的数据类型。具体的细节可以参考它们的论文(https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system)。HM算法是基于全局类型进行推导的,但是Scala有些许不同,因为Scala需要支持面向对象编程,所以它选择了局部的基于程序流的方式。 对于HM算法,下面的函数是成立的,但是Scala会报错:

代码语言:javascript
复制
scala> def sum(x:Int) = {if (x == 1) 1 else x + sum(x-1)}
<console>:7: error: recursive method sum needs result type
       def sum(x:Int) = {if (x == 1) 1 else x + sum(x-1)}

只能给sum函数的结果加上数据类型:

代码语言:javascript
复制
scala> def sum(x:Int):Int = {if (x == 1) 1 else x + sum(x-1)}
sum: (x: Int)Int

scala> sum(2)
res3: Int = 3

这里体现了基于局部的类型推断的局限,Scala无法推断出sum函数的返回类型。但是这样的处理方式会使得对子类型处理更加优雅。

代码语言:javascript
复制
scala> List(1,2,3,4)
res5: List[Int] = List(1, 2, 3, 4)

scala> List(1,"foo")
res6: List[Any] = List(1, foo)

我们可以通过局部的类型判断直接将异构的List判定为所有类型的父类Any。

现在再回到第一段代码: sortWith函数的可以通过List(1,2,3,4,5)进而推断出_>_等价于(x:Int,y:Int)=>x>y,而sort1如果传入的判断方法为_>_,Scala的类型推断无法根据sort1的类型推断出_>_的类型,自然就会报错了,而我们对sort1函数稍作修改:

代码语言:javascript
复制
scala> def sort1[T](xs:List[T])(cp:(T,T) => Boolean) = {xs sortWith (cp)}
sort1: [T](xs: List[T])(cp: (T, T) => Boolean)List[T]

scala> sort1(List(1,2,3,4,5))(_>_)
res0: List[Int] = List(5, 4, 3, 2, 1)

这样我们就可以借助Scala的类型推断,而不需要写(x:Int,y:Int)=>x>y这么长的语句了。除了修改原函数外,我们也可以使用类型参数,指定sort1的参数。

代码语言:javascript
复制
scala> def sort1[T](cp:(T,T) => Boolean)(xs:List[T]) = {xs sortWith (cp)}
sort1: [T](cp: (T, T) => Boolean)(xs: List[T])List[T]

scala> sort1[Int](_>_)(List(1,2,3,4,5))
res1: List[Int] = List(5, 4, 3, 2, 1)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-04-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 鸿的学习笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档