上下文绑定中的Type Lambda及类型别名的作用探讨
问题1:你的理解是否正确?Type Lambda在这里的作用是什么?
你的理解完全正确!我们来拆解一下为什么def test[T: Ordering[Option]]是无效的,以及Type Lambda在这里的核心作用:
首先,Scala的上下文绑定语法T: C要求C必须是一个单参数类型构造器(也就是kind为* -> *的类型),它本质是语法糖,会为方法隐式添加一个implicit ev: C[T]的参数。
而你尝试的Ordering[Option]本身是不合法的写法——Ordering是一个单参数的类型构造器(* -> *),它需要接收一个具体类型(kind为*)才能生成proper type。Option本身也是* -> *的构造器,直接写Ordering[Option]相当于把一个* -> *的构造器传给了需要*类型的Ordering,这在kind层面就不匹配。
再看你给出的Ordering相关定义:
trait OptionOrdering[T] extends Ordering[Option[T]] { def optionOrdering: Ordering[T] def compare(x: Option[T], y: Option[T]) = (x, y) match { case (None, None) => 0 case (None, _) => -1 case (_, None) => 1 case (Some(x), Some(y)) => optionOrdering.compare(x, y) } } implicit def Option[T](implicit ord: Ordering[T]): Ordering[Option[T]] = new OptionOrdering[T] { val optionOrdering = ord }
这里的Ordering[Option[T]]是一个proper type(kind为*),它是针对特定T的具体Ordering实例,而不是一个可以接收类型参数的构造器。
这时候Type Lambda(或者你定义的类型别名type L[x] = Ordering[Option[x]])的作用就是构建一个合法的* -> *类型构造器:
- 类型别名
L[x] = Ordering[Option[x]]把Ordering[Option[T]]这个proper type包装成了一个接收x参数的构造器,kind从*提升为* -> * - Type Lambda
({type L[x] = Ordering[Option[x]]})#L是内联的类型别名写法,作用和单独定义的L完全一致,只是不需要提前定义全局的类型别名,适合临时场景
这样上下文绑定T: L(或者内联的Type Lambda版本)就符合语法要求了,因为L是一个* -> *的构造器,编译器可以为T生成对应的implicit ev: L[T](也就是Ordering[Option[T]])参数。
问题2:带类型变量的类型别名在此场景的正式作用
带类型变量的类型别名在这里的核心作用是进行类型构造器的组合与kind提升:
从你提供的Scala控制台交互结果就能清楚看到:
scala> type e0 = Ordering[Option[_]] defined type alias e0 scala> :kind -v e0 e0's kind is A * This is a proper type.
Ordering[Option[_]]是一个proper type(kind为*),它代表的是某一类Ordering[Option[T]]的存在类型,但不能作为类型构造器接收新的类型参数。
而:
scala> type e1[w] = Ordering[Option[w]] defined type alias e1 scala> :kind -v e1 e1's kind is F[A] * -> * This is a type constructor: a 1st-order-kinded type.
带类型变量w的类型别名e1,把原本的proper type转换成了一个一阶类型构造器(* -> *)。它相当于一个“函数”,接收一个类型参数w,返回对应的Ordering[Option[w]]类型。
在上下文绑定的场景中,这个作用至关重要:它把原本无法直接用于上下文绑定的proper type,转换成了符合语法要求的类型构造器,让我们可以利用T: e1这样简洁的语法糖来声明隐式依赖。
内容的提问来源于stack exchange,提问作者MaatDeamon

