理解Scala类型系统中的Aux模式

理解Scala类型系统中的Aux模式,scala,shapeless,Scala,Shapeless,这个问题以前可能会被问到和回答,但我想通过一个例子来理解这一点,我无法解释Aux模式在哪里可能有用!这就是我的特点: trait Foo[A] { type B def value: B } 为什么我有一个绑定到value函数返回类型的类型?我这样做有什么收获?特别是,我应该在哪里使用这样的模式?想象一个typeclass来获取任何元组的最后一个元素 trait Last[A] { type B def last(a: A): B } object Last { type

这个问题以前可能会被问到和回答,但我想通过一个例子来理解这一点,我无法解释Aux模式在哪里可能有用!这就是我的特点:

trait Foo[A] {
  type B
  def value: B
}

为什么我有一个绑定到value函数返回类型的类型?我这样做有什么收获?特别是,我应该在哪里使用这样的模式?

想象一个typeclass来获取任何元组的最后一个元素

trait Last[A] {
  type B
  def last(a: A): B
}

object Last {
  type Aux[A,B0] = Last[A] { type B = B0 }

  implicit def tuple1Last[A]: Aux[Tuple1[A],A] = new Last[Tuple1[A]] {
    type B = A
    def last(a: Tuple1[A]) = a._1
  }

  implicit def tuple2Last[A,C]: Aux[(A,C),C] = new Last[(A,C)] {
    type B = C
    def last(a: (A,C)) = a._2
  }

  ...
}
类型
B
始终取决于类型
A
,这就是为什么
A
是类型类的输入类型,
B
是输出类型

现在,如果您想要一个可以根据最后一个元素对任何元组列表进行排序的函数,那么您需要访问同一参数列表中的
B
类型。这就是在Scala的当前状态下,您需要
Aux
模式的主要原因:当前无法在定义
last
的同一参数列表中引用
last.B
类型,也不可能有多个隐式参数列表

def sort[A,B](as: List[A])(implicit last: Last.Aux[A,B], ord: Ordering[B]) = as.sortBy(last.last)
当然,您总是可以完整地写出
Last[A]{typeb=B0}
,但显然,这很快就会变得非常不切实际(想象一下,添加两个具有依赖类型的隐式参数,这在Shapeless中非常常见);这就是
Aux
类型别名的由来。

相同的参数列表中支持启动Scala 3,这似乎使得
Aux
模式变得不必要,Jasper-M的代码片段简化为

trait Last[A]:
  type B
  def last(a: A): B

given [A]: Last[Tuple1[A]] with
  type B = A
  def last(a: Tuple1[A]) = a._1

given [A, C]: Last[(A,C)] with
  type B = C
  def last(a: (A,C)) = a._2

def sort[A](as: List[A])(using last: Last[A], ord: Ordering[last.B]) = as.sortBy(last.last)

sort(List(("ffle",3), ("fu",2), ("ker",1)))
// List((ker,1), (fu,2), (ffle,3))
请注意
last.B
的用法,其中
last
是来自中相同参数列表的值

def sort[A](as: List[A])(using last: Last[A], ord: Ordering[last.B])

类型B
的工作原理与A类似,只是它被命名并且可以被引用,与A相反。从技术上讲,您不需要使用
辅助模式来引用同一参数列表中的
last.B
;之所以选择它,是因为它比
隐式last:last[A]{type B=B0},Ordering[B0]
@breadmenace要简单得多是的,从技术上讲,您永远不需要Aux类型别名。我假设“Aux模式”指的是更广泛的模式,其中需要类型别名才能具有可接受的语法。newb问题-为什么隐式def(使用Aux的)的返回类型不能从计算值推断出来?@user2359636我很确定,如果允许,它们实际上是推断出来的,但不向隐式中添加类型注释是一种不好的做法。我认为多蒂已经宣布非注释隐式含义为非法。