必须完全知道匿名函数的参数类型。 (SLS 8.5)

时间:2012-10-13 01:48:52

标签: scala lambda pattern-matching function-literal

我有一个函数文字

{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,但这是语法错误。


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

3 个答案:

答案 0 :(得分:23)

{ 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)) 
}

虽然您应该重构以删除该可变状态。

答案 1 :(得分:7)

这里是SLS quote,对我们其他人来说:

  

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

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

答案 2 :(得分: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)) } }

我想知道为什么编译器不能使用开关类型来看我不打算使用部分函数然后用QualifiedType统一A.但事实并非如此。

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

//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)是否可以改进上面的开关定义,以及(b)是否已经有了我想要的库函数。


在Luigi的评论之后添加

这是最终的代码。是的,我认为这是折叠(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)) } ) 

感谢Luigi。