由于递归而导致真正复杂的逻辑被简化的情况,在日常编程中使用递归的情况
答案 0 :(得分:2)
递归的一个惊人的例子是Haskell和相关语言中的定点组合器:
fix f = f (fix f)
允许我们在没有显式递归的情况下编写递归函数:
fac = go (fix go) where
go g 0 = 1
go g n = n * g (n-1)
虽然它并没有那么有用,因为当然Haskell已经进行了递归。
更重要的是,同样的技巧也适用于类型级别。这是一个模拟文件系统的类型,如目录结构:
data DirEntry a = Dir [(String, a)] | File String
data Fix t = Y (t (Fix t))
type Directory = Fix DirEntry
通过这种方式,我们实际上可以使用类型
的值DirEntry (DirEntry (DirEntry (DirEntry ...))) -- nested arbitrarily deep
没有Directory
或DirEntry
本身是递归的。
答案 1 :(得分:1)
我最喜欢使用递归是蹦床。这是一种构建可组合代码的方便方法,它不会在没有尾调用消除的语言中溢出调用堆栈。
以下是Rich Dougherty’s blog的一个很好的例子:
sealed trait Bounce[A]
case class Done[A](result: A) extends Bounce[A]
case class Call[A](thunk: () => Bounce[A]) extends Bounce[A]
def even2(n: Int): Bounce[Boolean] = {
if (n == 0) Done(true)
else Call(() => odd2(n - 1))
}
def odd2(n: Int): Bounce[Boolean] = {
if (n == 0) Done(false)
else Call(() => even2(n - 1))
}
def trampoline[A](bounce: Bounce[A]): A = bounce match {
case Call(thunk) => trampoline(thunk())
case Done(x) => x
}
trampoline(even2(9999)) // false
我也强烈推荐RúnarÓli的paper on free monads。