Типы аргументов анонимной функции должны быть полностью известны. (SLS 8.5)
У меня есть литерал функции
{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) -> ...
.
Ответы
Ответ 1
Здесь цитата SLS, для остальных из нас:
Ожидаемый тип такого выражения должен быть определен частично. Это должно быть либо scala.Functionk[S1, . . . , Sk, R]
для некоторого k > 0, либо scala.PartialFunction[S1, R]
, где тип аргумента S1,.,, Sk должен быть полностью определен, но результат типа R может быть неопределенными.
В противном случае вы ответили на свой вопрос.
Ответ 2
{ 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))
}
хотя вы должны реорганизовать, чтобы удалить это изменяемое состояние.
Ответ 3
Вот почему я хотел использовать литерал функции и не хотел повторять этот тип дважды. Я пытался создать свою собственную конструкцию управления, чтобы отбросить весь код соответствия параметров. Если слишком много накладных расходов, то конструкция управления не помогает. Вот что я хотел сделать
//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, я должен иметь "определенный тип". Это потому, что этот литерал функции (тип с "случаем" ) предназначен для частичных функций, где аргумент может быть законным вообще. Я мог бы аргументировать свой литерал функции с помощью int, и это не было бы ошибкой типа, а просто причиной отказа всех шаблонов. Поэтому компилятору нужна некоторая информация "сверху вниз", чтобы узнать, какой тип я намерен использовать для параметра "расширенного литерала функции", то есть, что поставить для X в следующем
{(x : X) => x match {case Some(QualifiedType(preds, ty)) =>
Some((emptyEqualityConstraintSet,preds)) } }
Интересно, почему компилятор не может использовать тип коммутатора, чтобы увидеть, что я не нахожу частичную функцию, а затем унифицирую A с QualifiedType. Но это не так.
В любом случае он не компилируется. Но замена 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)) } )
Мне было бы интересно узнать (а), если вышеописанное определение коммутатора можно улучшить, и (б) если уже есть функция библиотеки, которая делает то, что я хочу.
Добавлено после комментария Луиджи
Вот окончательный код. Да, я думаю, что это складка (катаморфизм).
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)) } )
Благодаря Луиджи.