过去几个月我一直在使用功能语言从F#到Haskell再到Scheme(Racket)。我从来没有真正使用过递归,但Haskell及其模式匹配确实帮助我减少了对它们的恐惧。现在我正在使用Scheme,我似乎默认使用递归方法。我很好奇这是否表明只是经历了“o闪亮!”阶段或如果递归是Scheme开发的主要内容。
旁注:每当我编写递归方法时,我就一直在为尾递归拍摄。
答案 0 :(得分:10)
我认为这取决于你所说的是什么类型的递归。
第一个大开眼界(例如,如果你正在通过SICP工作)是迭代可以被递归取代。你在过去的生活中写过的所有那些乏味且容易出错的循环代码都可以用另一种方式完成。这是一个很酷的(如你所说)“哦,有光泽!”经验。
下一个令人大开眼界的是 那种类型的递归代码在现实生活中实际上会写得多少。相反,你可以通过使用像map
和fold
这样的构建块来避免繁琐的迭代 - 和繁琐的递归 -
此外,在Racket中,您可能会从map
和fold
毕业,而不喜欢for/list
,for/vector
和for/fold
这样的“理解”序列不仅仅是列表。在你继续前进的食物链上。
话虽如此,有些问题最好以递归方式解决(不只是“通过其他方式迭代”)。我认为,你在令人大开眼界的头号中获得的舒适度将会有所帮助。
答案 1 :(得分:5)
不,这不是一个阶段,它是一个主食。递归是一种技术,它允许您解决比您能够轻松解决的更复杂的问题 - 即使在您需要迭代解决方案的情况下,如果您首先制定递归解决方案,也更容易实现。
掌握递归也为您开辟了新的问题领域。典型的仅迭代程序员不具备处理问题的能力,例如,涉及在形式语言之间进行操作和转换,例如,基于报告的编码描述编写复杂的SQL查询生成器用户希望看到。
如果你想继续前进,你应该考虑使用折叠更加舒适,通过将递归计算的递归结构与递归步骤的内容分开,抽象远离显式递归。因此,例如,Scheme的fold-right
可以被视为“执行与此列表具有相同形状的递归计算,将空列表映射到此值作为基本情况,并将每个cons
映射到此函数。 “然后是其他更复杂的数据结构的折叠。
答案 2 :(得分:3)
每个都有一点。递归是Lisp的主要内容(不仅仅是Scheme)。但是,更高级的用户经常更多地使用其他控制流原语(尽管它们可能会以递归方式实现)。