所以,这听起来像是关于语言设计的一般性问题,但我认为这里有一些具体的东西。具体来说,我感兴趣的是哪些技术挑战可以防止随之而来的kludgy代码普遍有用。
我们都知道“Scala的类型推断不如Haskell那么好”,并且有很多原因它不能很好,并且仍然可以完成Scala所做的所有事情。但是,在Scala编程足够长的时候,很明显的是,糟糕的类型推断并不是那么糟糕,而是指定一些常见类型所需的详细程度。因此,例如,在多态tail
函数中,
def tail[A](ls: List[A]) =
ls match {
case Nil => sys.error("Empty list")
case x :: xs => xs
}
需要显式命名一个类型参数才能使该方法有用;没办法解决它。 tail(ls: List[Any])
将无法正常工作,因为Scala无法确定结果类型与输入类型相同,即使对于人类来说这是“显而易见的”。
因此,受到这种困难的启发,并且知道Scala有时可以使用类型成员比使用类型参数更聪明,我写了一个使用类型成员的List
版本:
sealed trait TMList {
self =>
type Of
def :::(x: Of) = new TMCons {
type Of = self.Of
val head = x
val tail = (self: TMList { type Of = self.Of })
}
}
abstract class TMNil extends TMList
def ATMNil[A] = new TMNil { type Of = A }
abstract class TMCons extends TMList {
self =>
val head: Of
val tail: TMList { type Of = self.Of }
}
好的,定义看起来很糟糕,但它至少是直截了当的,它允许我们按如下方式编写tail
方法:
def tail4(ls: TMList) =
ls match {
case _: TMNil => sys.error("Empty list")
case c: TMCons with ls.type => c.tail
}
美丽的是这个有效,所以我们可以写(按照你期望的那样定义head
)
val ls = 1 ::: 2 ::: ATMNil
val a = tail4(ls)
println(head4(a) * head4(a))
和Scala 知道输出类型成员仍为Int
。我们不得不用TMCons with ls.type
写一些有趣的东西,并且Scala抱怨这个匹配并不详尽,但Scala为我们插入了一些代码,因为当然你匹配{{1任何情况都必须是ls
,当然这场比赛是详尽无遗的。
所以我的问题是:抓到了什么?为什么我们不这样做我们所有的多态类型,只修改语言,所以语法看起来不那么糟糕?我们会遇到哪些技术问题?
显然,有一个类在其类型成员中不能协变;但我对此并不那么感兴趣;我认为这是一个单独的问题。假设我们暂时不关心方差。还有什么会出错?
我怀疑这可能会为类型推断引入新的问题(比如我必须为示例定义ls.type
),但我不太了解Scala的类型推断,以便知道它们会是什么。< / p>
编辑以回复0 __:我想您可能已找到它。具有类型参数的版本可以使用
ATMNil
但有趣的是,如果没有明确的返回类型,那么一个curried依赖类型的版本就不会:
def move2[A](a: TMList { type Of = A }, b: TMList { type Of = A }) = b match {
case c: TMCons with b.type => c.head ::: a
case _ => a
}
Scala将返回类型推断为def move3(a: TMList)(b: TMList { type Of = a.Of }) = b match {
case c: TMCons with b.type => c.head ::: a
case _ => a
}
;此是两种类型案例的上限,TMList
和TMList { type Of = a.Of }
。当然,a.type
也是一个上限(也就是我想要的那个,这就是为什么添加一个显式的返回类型有效),而且,我认为,更具体的上限。我想知道为什么Scala没有推断出更具体的上限。
答案 0 :(得分:6)
答案 1 :(得分:2)
尝试使用TMList
重写以下内容:
def move[A](a: List[A], b: List[A]): List[A] = b match {
case head :: _ => head :: a
case _ => a
}
move(List(1,2,3),List(4,5,6))