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.
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?
(b) What can I do to fix it?
I tried the obvious fix, which was to add : QualifiedType
between the pattern and the =>, but this is a syntax error.
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) -> ...
.
Here's the SLS quote, for the rest of us:
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.
Otherwise, you answered your question.
{ 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 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.
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
{(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.
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.
//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.
Added after Luigi's Comment
Here is the final code. Yes, I think it is a fold (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.