Подтвердить что ты не робот

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

4b9b3361

Ответ 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)) } ) 

Благодаря Луиджи.