为什么Scala需要递归函数的返回类型?
在下面包含的代码片段中,我有一个递归函数调用,用于在网络调用失败时促进重试(Amazon SimpleDB偶尔会返回503并要求重试) 当我尝试编译时,Scala抱怨递归方法simpledb\u update需要结果类型为什么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 {
// 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){