Зачем этому коду нужна пустая строка или точка с запятой? - PullRequest
5 голосов
/ 17 сентября 2010
case class MyInt(val i : Int) {
    private def factorial(a : Int) : Int = a match {
        case 0 => 1
        case n => (n) * factorial(n-1)
    }
    def ! = factorial(i)
    override def toString = i.toString
}

object MyInt {
    implicit def intToMyInt(x : Int) = MyInt(x)
    implicit def myIntToInt(x : MyInt) = x.i
}
import MyInt._

object Factorial {  
    def main(args: Array[String]): Unit = {
        val a = 5
        val aFact = a!
        println("factorial of " + a + " is " + aFact)

  }
}

Если я не поставлю точку с запятой или пустую строку до println, она не скомпилируется:

рекурсивное значение aFact нуждается в типе

Ответы [ 3 ]

10 голосов
/ 18 сентября 2010

Все эти разговоры о рекурсивной функции и типе - это красная сельдь.Грамматика 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

Так что это выглядит как правильное выражение инфикса для компилятора, когда он анализировал вашу программу.После этого он заметил, что типы не совпадают, но уже слишком поздно возвращаться и проверять, можно ли заключить точку с запятой.

6 голосов
/ 17 сентября 2010

Потому что в противном случае ! можно интерпретировать как двоичное выражение

a ! println("factorial of " + a + " is " + aFact)

Противоположное можно было бы доказать, только если компилятор оценил оба типа задействованных выражений, потому что существует возможность неявного преобразования для этих типов, которое разрешило вызов.

Но так как правильный операнд включает в себя aFact, значение является рекурсивным, Scala не может определить его тип и, следовательно, не правильную корректность оператора.

Вы должны быть явными здесь!

1 голос
/ 17 сентября 2010

Ниже код компилируется нормально:

package it.onof.scalaDemo

case class MyInt(val i : Int) {
    private def factorial(a : Int) : Int = a match {
        case 0 => 1
        case n => (n) * factorial(n-1)
    }
    def ! = factorial(i)
    override def toString = i.toString
}

object MyInt {
    implicit def intToMyInt(x : Int) = MyInt(x)
    implicit def myIntToInt(x : MyInt) = x.i
}
import MyInt._

object Factorial {  
    def main(args: Array[String]): Unit = {
        val a = 5
        val aFact:Int = a.!
        println("factorial of " + a + " is " + aFact)
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...