接上文,我们以函数的视角来看待类型系统中的高阶特性,与一阶函数,高阶函数对比:

这种kind表达方式与函数的lambda很相似。实际上scala也确实支持(受限版本的) type lambda,(注,从scala in depth这本书中看到,后续的例子也是引自这本书)
// 定义一个函数,带类型参数
scala> def foo[M[_]] (f : M[Int]) = f
scala> foo[List] ( List(1,2,3) )
res9: List[Int] = List(1, 2, 3)
scala> foo ( List(1,2,3) ) // 类型参数可以省略,编译器会推断
res9: List[Int] = List(1, 2, 3)
现在,在不改变方法声明的情况下,如何让下面这句通过?
scala> foo( (x:Int) => println(x) ) // 如何让这句能编译通过?
foo函数在定义时,参数类型必须是泛型类型。而 (x:Int) => println(x)
是一段匿名函数(lambda),它的类型是 Int=>Unit
而Scala中的函数,在实现上是通过FunctionN这个类来封装的;对于Int=>Unit
这样的函数类型,背后其实是:
Function1[Int, Unit]
这么看的话,Function1
类型也是一个泛型类型,只不过它的类型参数有2个,而我们定义的foo函数的类型参数是只有一个类型参数的泛型,如果直接调用的话,很明显不符合类型约束。
所以这里引入了type lambda
,我们可以通过type lambda
来把类型转换为符合约束的形式:
scala> foo[ ({type X[Y] = Function1[Y, Unit]})#X ] ( (x:Int)=>print(x) )
res5: Int => Unit = <function1>
现在我们来分析一下 ({type X[Y] = Function1[Y, Unit]})#X
这段类型表达式(type lambda)是什么意思?
首先,假定你了解scala里type的用法,这里定义了一个类型别名:X[Y]
type X[Y] = Function1[Y, Unit]
X[Y]
这个类型等价于 Function1[Y, Unit]
。而把它用大括号括起来是什么意思?
{type X[Y] = Function1[Y, Unit]}
注意,这里的上下文是类型声明,在类型声明中,大括号用来表示结构类型(structural type),比如:
def using[ C <% { def close(): Unit } ](resource: C) {
…
}
上面using
函数里类型声明时定义了一个结构类型{ def close(): Unit }
表示一个任何存在close方法的类型。
所以{type X[Y] = Function1[Y, Unit]}
就表示了这样一个匿名类型:对任何Function1[Y, Unit]
类型,定义一个了别名为X[Y]
的类型。
然后通过(…)#X
的方式来获取这个匿名类型中的X
类型,而这个X
是符合foo函数的类型参数约束的。