2014-09-02 127 views
0

我有一些递归代码我想重构使用从Enumerator尾递归,我可以简化递归看起来像这样,请忽略此功能要实现的功能。可以函数尾递归

@tailrec 
def doStuff: List[Int] => Int = { 
     case Nil => 0 
     case x :: xs => doStuff(xs) 
    } 

如果我摆脱tailrec注释,它做工精细,结构看起来像这样doStuff(doStuff(doStuff(..)))。它会有stackoverflow异常。

所以,我怎样才能使尾递归如果是

回答

5

匿名函数不能进行尾递归。让我们先对代码进行一次非常简单的重写,以引入一个val来保存结果函数。

@tailrec 
def doStuff: List[Int] => Int = { 
    val result: List[Int] => Int = { 
    case Nil => 0 
    case x :: xs => doStuff(xs) 
    } 
    result 
} 

应该清楚,从那里,那是doStuff(xs)调用匿名函数本身。它调用方法doStuff,其中返回您要调用的函数。更糟的是,由于它是def,它实际上在每次呼叫时都会返回一个不同的功能。因此匿名函数绝对不会调用本身

这个问题概括为这个简单的事实:匿名函数是匿名的。所以他们无法直接调用自己:他们总是调用一些可能自行返回的defval,但编译器不知道。

由于这个原因,只有合适的def像@dhg提出的那样才真正是尾递归的。

现在,如果您确实想要返回一个函数值,那恰好是使用尾递归的情况来实现的,那么您可以简单地使用theMethod _将函数转换为函数。因此,解决您最初的问题是以下几点:

val doStuff = { 
    @tailrec 
    def rec(list: List[Int]): Int = list match { 
    case Nil => 0 
    case x :: xs => rec(xs) 
    } 
    rec _ 
} 

请注意,我们声明一个适当的尾递归方法rec),我们则变成一个函数值与rec _

1

也许你的意思是这样的功能?

@tailrec 
def doStuff(list: List[Int]): Int = list match { 
    case Nil => 0 
    case x :: xs => doStuff(xs) 
} 
+0

不是真的,这是Int的返回类型,我仍然想返回类型为一个函数。如果你看一下这个http://blog.higher-order.com/blog/2010/10/14/scalaz-tutorial-enumeration-based-io-with-iteratees/中enumerateFile的实现。几乎所有的递归函数都不是尾递归的。这是我想改变的。 – 2014-09-02 04:19:28

+0

@Cloudtech [你可以用'doStuff _'调用把它变成函数值](http://scalafiddle.net/console/7bd66825e9a97424ffe5645549270832) – 2014-09-02 13:24:58

0

所以,我怎样才能使尾递归如果它是一个功能

你不能。我的意思是,当然你可以在Scala中编写一个尾递归函数,但它不会帮助你,因为它不会被优化。

Scala只优化直接尾递归方法调用。