Все эти разговоры о рекурсивной функции и типе - это красная сельдь.Грамматика Scala не допускает использование постфиксных операторов в любом другом месте, кроме конца выражения.Это грамматика, о которой мы говорим: синтаксис вещей без какой-либо семантики.Вот соответствующая грамматика из спецификации:
Expr ::= (Bindings | [‘implicit’] id | ‘_’) ‘=>’ Expr
| Expr1
Expr1 ::= ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[semi] else Expr]
| ‘while’ ‘(’ Expr ‘)’ {nl} Expr
| ‘try’ ‘{’ Block ‘}’ [‘catch’ ‘{’ CaseClauses ‘}’]
[‘finally’ Expr]
| ‘do’ Expr [semi] ‘while’ ‘(’ Expr ’)’
| ‘for’ (‘(’ Enumerators ‘)’ | ‘{’ Enumerators ‘}’)
| {nl} [‘yield’] Expr
| ‘throw’ Expr
| ‘return’ [Expr]
| [SimpleExpr ‘.’] id ‘=’ Expr
| SimpleExpr1 ArgumentExprs ‘=’ Expr
| PostfixExpr
| PostfixExpr Ascription
| PostfixExpr ‘match’ ‘{’ CaseClauses ‘}’
PostfixExpr ::= InfixExpr [id [nl]]
Единственные два места, где рядом с ними появляется PostfixExpr
, это после if
в операторе case
и до : _*
в списке аргументов,Итак, глядя на это, мы видим, что единственное, что может появиться в правой части имени метода выражения postfix, - это тип ascription или match
.
Итак, каковы конечные выражения?Ну, выражения появляются во многих местах в грамматике, так что есть много вещей, которые могут положить этому конец.В этом конкретном примере выражение является BlockStat
внутри Block
, поэтому оно должно заканчиваться точкой с запятой, которая может быть выведена или нет.
Чтобы вывести эту точку с запятой,необходимо, чтобы следующая строка не была чем-то, что можно было бы проанализировать как выражение другого типа.В данном конкретном случае у нас есть это:
val aFact = a!
println("factorial of " + a + " is " + aFact)
Теперь давайте перепишем это с точки зрения компилятора:
val id = id id
id ( stringLit id id id stringLit id id )
Эти литералы и идентификаторы анализируются следующим образом:
val id = id id id ( expr )
val Pattern2 = SimpleExpr1 id SimpleExpr1 ArgumentExprs
val Pattern2 = InfixExpr
val Pattern2 = Expr
val PatDef
PatVarDef
Def
BlockStat
Так что это выглядит как правильное выражение инфикса для компилятора, когда он анализировал вашу программу.После этого он заметил, что типы не совпадают, но уже слишком поздно возвращаться и проверять, можно ли заключить точку с запятой.