有时我偶然发现了半神秘的符号
def f[T](..) = new T[({type l[A]=SomeType[A,..]})#l] {..}
在 Scala 博客文章中,它给出了“我们使用了 type-lambda 技巧”的手势。
虽然我对此有一些直觉(我们获得了一个匿名类型参数 A
而不必用它污染定义?),但我没有找到明确的来源来描述 lambda 类型技巧是什么,并且它有什么好处。它只是语法糖,还是打开了一些新的维度?
最佳答案
当您使用更高级的类型时,类型 lambda 在很多时候都至关重要。
考虑一个为 Either[A, B] 的右投影定义 monad 的简单示例。 monad 类型类如下所示:
trait Monad[M[_]] {
def point[A](a: A): M[A]
def bind[A, B](m: M[A])(f: A => M[B]): M[B]
}
现在,Either 是两个参数的类型构造函数,但要实现 Monad,您需要为其提供一个参数的类型构造函数。解决这个问题的方法是使用 lambda 类型:
class EitherMonad[A] extends Monad[({type λ[α] = Either[A, α]})#λ] {
def point[B](b: B): Either[A, B]
def bind[B, C](m: Either[A, B])(f: B => Either[A, C]): Either[A, C]
}
这是类型系统中柯里化(Currying)的一个示例 - 您已经柯里化(Currying)了 Either 的类型,这样当您想要创建 EitherMonad 的实例时,您必须指定其中一种类型;另一个当然是在您调用点或绑定(bind)时提供的。
类型 lambda 技巧利用了这样一个事实:类型位置中的空 block 会创建匿名结构类型。然后我们使用 # 语法来获取类型成员。
在某些情况下,您可能需要更复杂的类型 lambda,但内联编写起来很困难。这是我今天的代码中的一个示例:
// types X and E are defined in an enclosing scope
private[iteratee] class FG[F[_[_], _], G[_]] {
type FGA[A] = F[G, A]
type IterateeM[A] = IterateeT[X, E, FGA, A]
}
这个类的存在是为了让我可以使用像 FG[F, G]#IterateeM 这样的名称来引用专门用于第二个 monad 的某些转换器版本的 IterateeT monad 的类型,而第二个 monad 专门用于某些第三个 monad。当你开始堆叠时,这些类型的构造就变得非常必要。当然,我从不实例化 FG;它只是作为一种技巧让我在类型系统中表达我想要的内容。
关于scala - Scala 中的 lambda 类型是什么?它们有什么好处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8736164/