为什么Scala需要递归函数的返回类型?

为什么Scala需要递归函数的返回类型?,scala,Scala,在下面包含的代码片段中,我有一个递归函数调用,用于在网络调用失败时促进重试(Amazon SimpleDB偶尔会返回503并要求重试) 当我尝试编译时,Scala抱怨递归方法simpledb\u update需要结果类型 // sends data to SimpleDB. Retries if necessary def simpledb_update(name: String, metadata: Map[String,String], attempt: Int) = { try {

在下面包含的代码片段中,我有一个递归函数调用,用于在网络调用失败时促进重试(Amazon SimpleDB偶尔会返回503并要求重试)

当我尝试编译时,Scala抱怨递归方法simpledb\u update需要结果类型

// sends data to SimpleDB. Retries if necessary
def simpledb_update(name: String, metadata: Map[String,String], attempt: Int) = {
 try {
  db(config("simpledb_db")) += (name, metadata)
 } catch {
  case e =>
   // if it fails, try again up to 5 times
  if(attempt < 6)
  {
   Thread.sleep(500)
   simpledb_update(name, metadata, attempt + 1)
   } else
     AUlog(name + ": SimpleDB Failed")
   }
 }
//将数据发送到SimpleDB。必要时重试
def simpledb_更新(名称:String,元数据:Map[String,String],尝试:Int)={
试一试{
数据库(配置(“simpledb”)+=(名称、元数据)
}抓住{
案例e=>
//如果失败,请重试最多5次
如果(尝试次数<6)
{
线程。睡眠(500)
simpledb_更新(名称、元数据、尝试次数+1)
}否则
AUlog(名称+“:SimpleDB失败”)
}
}
为什么递归函数需要这样做?我的想法是只返回一个真/假布尔值来满足编译器。。。下面的代码编译得很好

// sends data to SimpleDB. Retries if necessary
 def simpledb_update(name: String, metadata: Map[String,String], attempt: Int): Boolean = {
 try {
  db(config("simpledb_db")) += (name, metadata)
  true
 } catch {
  case e =>
   // if it fails, try again up to 5 times
   if(attempt < 6)
   {
    Thread.sleep(500)
    simpledb_update(name, metadata, attempt + 1)
   } else
    AUlog(name + ": SimpleDB Failed")
    false
  }
}
//将数据发送到SimpleDB。必要时重试
def simpledb_更新(名称:字符串,元数据:映射[String,String],尝试:Int):布尔={
试一试{
数据库(配置(“simpledb”)+=(名称、元数据)
真的
}抓住{
案例e=>
//如果失败,请重试最多5次
如果(尝试次数<6)
{
线程。睡眠(500)
simpledb_更新(名称、元数据、尝试次数+1)
}否则
AUlog(名称+“:SimpleDB失败”)
假的
}
}

只需将=从行中删除,它将返回单元,这意味着您无需返回任何内容

def simpledb_update(name: String, metadata: Map[String,String], attempt: Int) {

我认为需要返回类型,这是为了确保所有递归路径都具有正确的类型。在普通函数上,将从所有返回点推断类型。

据我所知,递归函数需要返回类型,因为类型推断算法的功能不足以确定所有递归函数的返回类型

但是,您不需要创建返回类型,只需要声明已经使用的返回类型:Unit。单元是一种特殊类型,只有一个元素()。它也是Scala中大多数“语句”的类型,并且是为不需要返回任何内容,但仅针对其副作用执行的方法(就像您的方法一样)声明的返回类型。您可以像其他类型一样将方法声明为返回单元

def simpledb_update(name: String, metadata: Map[String,String], attempt: Int):Unit = {
更惯用的是Scala为单元返回方法提供了一种特殊的语法,只需去掉返回类型和等号即可

根据scala样式指南,您应该更喜欢使用等号


您无法从返回点推断类型,因为至少有一个返回点具有您正试图推断的类型。@Jorg-事实上,这并不难推断(但可能比您想要的更难)。如果得到的每个路径返回值的类型不是递归返回值,则该类型必须是返回值的类型。但是当被推到相互递归的函数中时,这会变得复杂。这就像尾部递归。得到的许多方程都是可解的,而且没有太多困难。问题是并非所有的方程都是可解的。语言规范需要声明亮线规则,根据这些规则,编译器可以解决所有可接受的结构,并且所有不可接受的结构都有一条简短的错误消息,说明它们不可接受的原因。“递归方法需要显式返回类型”是Scala的一个亮点规则,希望不会太繁琐。类似:Psst,如果您使用的是2.8,请使用
trunt:Int=0
,这样您的原始调用就不需要指定它是第0次尝试!此外,如果执行任何深度递归操作,可能会使堆栈溢出(当然,6是可以的)。要检查Scala是否可以避免使用堆栈,请在
def
之前使用
@annotation.tailrec
对其进行注释。如果不是尾部递归,则必须使用堆栈,Scala将抛出一个错误——这样至少您知道在删除注释时要处理什么。唉,我在2.7。。。不受支持!我想是时候升级了。为什么类型推断算法不足以确定所有递归函数的返回类型?字面上引用“不耐烦的Scala”:一些编程语言(如ML和Haskell)可以使用Hindley-Milner算法推断递归函数的类型。然而,这在面向对象语言中并不适用。扩展Hindley-Milner算法以使其能够处理子类型仍然是一个研究问题。
def simpledb_update(name: String, metadata: Map[String,String], attempt: Int){