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)
}
}
Run Code Online (Sandbox Code Playgroud)
如果我在println编译失败之前没有添加分号或空行:
递归值aFact需要类型
Dan*_*ral 10
所有关于递归函数和类型的讨论都是红鲱鱼.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]]
Run Code Online (Sandbox Code Playgroud)
PostfixExpr旁边出现的唯一两个地方是if在一个case声明之后和: _*一个参数列表之前.所以,看一下,我们看到在postfix表达式的方法名称的右侧可以出现的唯一的东西是类型ascription或a match.
那么,什么结束表达?好吧,表达式出现在语法的很多地方,所以有很多东西可以结束它.在这个特定的例子中,表达式是a的BlockStat内部Block,因此它必须以分号结尾,这可以是推断的或不推断的.
要推断出这种分号,下一行必须不能被解析为另一种表达式.在这种特殊情况下,我们有:
val aFact = a!
println("factorial of " + a + " is " + aFact)
Run Code Online (Sandbox Code Playgroud)
现在,让我们从编译器的角度重写它:
val id = id id
id ( stringLit id id id stringLit id id )
Run Code Online (Sandbox Code Playgroud)
这些文字和标识符的解析方式如下:
val id = id id id ( expr )
val Pattern2 = SimpleExpr1 id SimpleExpr1 ArgumentExprs
val Pattern2 = InfixExpr
val Pattern2 = Expr
val PatDef
PatVarDef
Def
BlockStat
Run Code Online (Sandbox Code Playgroud)
因此,在解析程序时,它看起来像编译器的有效中缀表达式.之后,它注意到类型不匹配,但是回去看看是否可以推断出分号已经太晚了.
因为否则!可以将其解释为二进制表达式
a ! println("factorial of " + a + " is " + aFact)
Run Code Online (Sandbox Code Playgroud)
如果编译器推翻了所涉及的表达式的两种类型,则可以证明相反的情况,因为存在允许调用的这些类型的隐式转换的可能性.
但由于右操作数涉及aFact自身,因此值是递归的,Scala无法确定它的类型,因此不能确定操作符的正确性.
你需要在这里明确!
| 归档时间: |
|
| 查看次数: |
1350 次 |
| 最近记录: |