Типы аргументов анонимной функции должны быть полностью известны. (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)) }}
ошибка уходит.
а) Почему это ошибка?
(б) Что я могу сделать, чтобы это исправить?
Я попробовал очевидное исправление, которое должно было добавить : QualifiedType
между шаблоном и =>, но это синтаксическая ошибка.
Одна вещь, которую я заметил, заключается в том, что контекст имеет значение. Если я использую литерал функции в качестве аргумента функции, объявленной как ожидающая QualifiedType => B
Нет ошибки. Но если я использую его в качестве аргумента для функции, ожидающей A => B
есть ошибка. Я ожидаю, что здесь происходит то, что, поскольку шаблон может быть применен к объекту, тип которого является супертипом QualifiedType, компилятор не желает назначать очевидный тип без гарантии того, что функция не будет применена к все, что не является QualifiedType. На самом деле я хотел бы иметь возможность писать {QualifiedType( preds, ty) => ...}
и это означает то же самое, что и у Хаскелла \QualifiedType(preds,ty) -> ...
,
3 ответа
Вот цитата SLS для остальных из нас:
Ожидаемый тип такого выражения должен быть частично определен. Это должно быть либо
scala.Functionk[S1, . . . , Sk, R]
для некоторого k > 0 илиscala.PartialFunction[S1, R]
где тип аргумента (ов) S1, .,, Sk должен быть полностью определен, но тип результата R может быть неопределенным.
В противном случае вы ответили на свой вопрос.
{ 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))
}
хотя вы должны рефакторинг, чтобы удалить это изменчивое состояние.
Вот почему я хотел использовать литерал функции и не хотел повторять тип дважды. Я пытался создать свою собственную управляющую конструкцию, чтобы вычленить весь код соответствия опций. Если накладных расходов слишком много, то управляющая конструкция не помогает никому. Вот что я хотел сделать
//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)) } }
Интересно, почему компилятор не смог использовать тип переключателя, чтобы увидеть, что я не собираюсь использовать частичную функцию, а затем объединить 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)) } )
Спасибо Луиджи.