Типы аргументов анонимной функции должны быть полностью известны. (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)) } ) 

Спасибо Луиджи.

Другие вопросы по тегам