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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12869251/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 04:37:23  来源:igfitidea点击:

The argument types of an anonymous function must be fully known. (SLS 8.5)

scalalambdapattern-matchingfunction-literal

提问by Theodore Norvell

I have a function literal

我有一个函数文字

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

Which results in an error message

这会导致错误消息

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)]

I looked in SLS 8.5, but didn't find an explanation.

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

If I expand the function myself to

如果我自己将函数扩展为

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

the error goes away.

错误消失了。

(a) Why is this an error?

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

(b) What can I do to fix it?

(b) 我能做些什么来修复它?

I tried the obvious fix, which was to add : QualifiedTypebetween the pattern and the =>, but this is a syntax error.

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



One thing I noticed is that the context makes a difference. If I use the function literal as an argument to a function declared as expecting a QualifiedType => B, there is no error. But if I use it as an argument to a function expecting an A => B, there is an error. I expect that what is going on here is that, as the pattern could conceivably be applied to an object whose type is a supertype of QualifiedType, the compiler is not willing to assign the obvious type without assurance that the function won't be applied to anything that isn't a QualifiedType. Really what I'd like is to be able to write {QualifiedType( preds, ty) => ...}and have it mean the same thing as Haskell's \QualifiedType(preds,ty) -> ....

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

采纳答案by som-snytt

Here's the SLS quote, for the rest of us:

这是我们其他人的SLS 报价

The expected type of such an expression must in part be defined. It must be either scala.Functionk[S1, . . . , Sk, R]for some k > 0, or scala.PartialFunction[S1, R], where the argument type(s) S1, . . . , Sk must be fully determined, but the result type R may be undetermined.

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

Otherwise, you answered your question.

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

回答by Luigi Plinge

{ case X(x) => ... }is a partial function, but the compiler still doesn't know what your input type is, except that it's a supertype of X. Normally this isn't a problem because if you're writing an anonymous function, the type is known from the context. But here is how you can provide the type:

{ 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

As you've probably noticed, using function literals / pattern matching here is pretty pointless. It seems in your case you just need a regular method:

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

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

although you should refactor to remove that mutable state.

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

回答by Theodore Norvell

Here is why I wanted to use a function literal and didn't like having to repeat the type twice. I was trying to build my own control construct to factor out all the option matching code. If there is too much overhead, then the control construct doesn't help any. Here is what I wanted to do

这就是为什么我想使用函数文字并且不想重复两次类型。我试图构建我自己的控制结构来分解所有选项匹配代码。如果开销太大,那么控制结构就无济于事。这是我想做的

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

The switch control construct compiles fine, but the usage caused an error because the SLS says that where I have an A, I should have a "definite type". That's because this kind of function literal (the kind with "case") is intended for partial functions where the argument could be legitimately any thing at all. I could argue my function literal with an int and that would not be a type error, but merely a matter of all the patterns failing. So the compiler needs some "top down" information to know what type I intend for the parameter of the "expanded function literal", i.e. what to put for X in the following

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

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

I wonder why the compiler could't use the type of switch to see that I don't intend a partial function and then unify A with QualifiedType. But it doesn't.

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

Anyway it doesn't compile. But replacing A with Any eliminates the error. The following code actually compiles. What I lose is some type checking.

无论如何它不编译。但是用 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)) } ) 

I'd be interested to know (a) if the above definition of switch can be improved, and (b) if there is already a library function that does what I want.

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



Added after Luigi's Comment

在 Luigi 的评论后添加

Here is the final code. Yes, I think it is a fold (catamorphism).

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

Thanks to Luigi.

感谢路易吉。