44

我有一个函数文字

{case QualifiedType(preds, ty) =>
               t.ty = ty ;
               Some((emptyEqualityConstraintSet,preds)) }

这会导致错误消息

missing parameter type for expanded function The argument types of an anonymous function
must be fully known. (SLS 8.5) Expected type was:
? => Option[(Typer.this.EqualityConstraintSet, Typer.this.TypeRelationSet)]

我查看了SLS 8.5,但没有找到解释。

如果我自己将功能扩展为

{(qt : QualifiedType) =>
  qt match {case QualifiedType(preds, ty) =>
               t.ty = ty ;
               Some((emptyEqualityConstraintSet,preds)) }}

错误消失了。

(a) 为什么这是一个错误?

(b) 我能做些什么来解决它?

我尝试了明显的修复,即: QualifiedType在模式和 => 之间添加,但这是一个语法错误。


我注意到的一件事是上下文有所不同。如果我使用函数文字作为声明为期望 a 的函数的参数QualifiedType => B,则没有错误。但是,如果我将它用作期望 a 的函数的参数A => B,则会出现错误。我希望这里发生的事情是,由于可以想象该模式可以应用于类型是 QualifiedType 的超类型的对象,编译器不愿意在不保证函数不会应用于的情况下分配明显的类型任何不是 QualifiedType 的东西。我真正想要的是能够编写{QualifiedType( preds, ty) => ...} 并使其与 Haskell 具有相同的含义\QualifiedType(preds,ty) -> ...

4

3 回答 3

39

{ case X(x) => ... }是一个偏函数,但编译器仍然不知道你的输入类型是什么,除了它是X. 通常这不是问题,因为如果您正在编写匿名函数,则类型是从上下文中知道的。但您可以通过以下方式提供类型:

case class Foo(x: Int)

// via annotation
val f: Foo => Int = { case Foo(x) => x }

// use pattern matching
val f = (_: Foo) match { case Foo(x) => x }

// or more normally, write as a method
def f(a: Foo) = a match { case Foo(x) => x }
def f(a: Foo) = a.x

您可能已经注意到,在这里使用函数文字/模式匹配是毫无意义的。在您的情况下,您似乎只需要一个常规方法:

def whatever(qt: QualifiedType) = {
  t.ty = qt.ty
  Some((emptyEqualityConstraintSet, qt.preds)) 
}

尽管您应该重构以删除该可变状态。

于 2012-10-13T03:06:26.293 回答
7

这是我们其他人的SLS 报价

必须部分定义此类表达式的预期类型。它必须是scala.Functionk[S1, . . . , Sk, R]对于某些 k > 0 或 scala.PartialFunction[S1, R],其中参数类型 S1, 。. . , Sk 必须是完全确定的,但结果类型 R 可能是不确定的。

否则,你回答了你的问题。

于 2012-10-13T02:32:33.593 回答
4

这就是为什么我想使用函数文字并且不喜欢重复两次的原因。我试图构建自己的控件构造来分解所有选项匹配代码。如果开销太大,那么控制构造就没有任何帮助。这是我想做的

//This is the control construct definition
def switch[A,B]( x : Option[A], noneFun : =>B, someFun : A=>B) = x match {
    case None => noneFun 
    case Some(y) => someFun(y) }

//And this is an example of using it.
def foobar( qt : Option[QualifiedType]  ) = 
    switch( qt, {reportError("SNAFU");None},
            {case QualifiedType(preds, ty) =>
               Some((emptyEqualityConstraintSet,preds)) } ) 

开关控制结构编译得很好,但使用导致错误,因为 SLS 说我有一个 A,我应该有一个“确定的类型”。这是因为这种函数字面量(带有“case”的那种)适用于参数可以合法地是任何东西的部分函数。我可以用 int 来争论我的函数字面量,这不会是类型错误,而仅仅是所有模式都失败的问题。所以编译器需要一些“自上而下”的信息来知道我打算为“扩展函数文字”的参数使用什么类型,即在下面为 X 放置什么

{(x : X) => x match {case Some(QualifiedType(preds, ty)) =>
               Some((emptyEqualityConstraintSet,preds)) } }

我想知道为什么编译器不能使用 switch 的类型来查看我不打算使用部分函数,​​然后将 A 与 QualifiedType 统一起来。但事实并非如此。

无论如何它不会编译。但是用 Any 替换 A 可以消除错误。以下代码实际编译。我失去的是一些类型检查。

//This is the control construct definition
def switch[A,B]( x : Option[A], noneFun : =>B, someFun : A=>B) = x match {
    case None => noneFun 
    case Some(y) => someFun(y) }

//And this is an example of using it.
def foobar( qt : Option[QualifiedType]  ) = 
    switch( qt, {reportError("SNAFU");None},
            {case QualifiedType(preds, ty) =>
               Some((emptyEqualityConstraintSet,preds)) } ) 

我很想知道(a)是否可以改进上述 switch 的定义,以及(b)是否已经有一个库函数可以满足我的需求。


在路易吉的评论之后添加

这是最终的代码。是的,我认为这是一个折叠(catamorphism)。

def switch[A,B]( x : Option[A])(noneFun : =>B, someFun : A=>B) = x match {
    case None => noneFun 
    case Some(y) => someFun(y) }

def foobar( qt : Option[QualifiedType]  ) : Option[(EqualityConstraintSet, TypeRelationSet)] =
    switch( qt )({reportError("SNAFU");None},
            {case QualifiedType(preds, ty) =>
               Some((emptyEqualityConstraintSet,preds)) } ) 

感谢路易吉。

于 2012-10-13T19:52:05.670 回答