9
  • 我想知道:可以在函数式编程中完成无限循环吗?

例子:使用windows API获取windows消息时,通常是循环实现的。

我知道可以创建一个无限期地继续递归的函数。我希望这会导致堆栈溢出。

  • 无限循环是函数式编程的错误思维方式吗?

  • 是操作系统的接口还是硬件的问题?

在我看来,功能性程序/操作系统无法自行运行

我有一点编写函数式程序的经验,但这一直困扰着我。请分享您对这些问题的想法/见解

4

4 回答 4

5

如果你使用尾递归,你实际上有一个迭代,就像一个 for/while 循环。因此,我猜你可以有一个无限循环而不会导致堆栈溢出。

对于您的问题:“无限循环是函数式编程的错误思维方式吗?” 也许这会有所帮助: - F# 中的 While 或 Tail Recursion,什么时候使用?

于 2010-08-14T15:07:29.607 回答
5

正如其他人所发布的那样,通过尾递归可以实现无限循环。

例如loop(),将有效地作为无限循环运行(在恒定堆栈空间中),因为编译器可以优化最后的尾递归调用loop

let loop() = do {
  println("foo")
  loop()
}

无限循环是函数式编程的错误思维方式吗?

还是有道理的。考虑带有无限循环的 Windows-API 示例。那不是功能性的。请记住——功能性意味着思考价值观(以及它们的含义)。因此,人们宁愿采用类似 [Pseudo-functional code] 的反应式/基于事件的方法

  (onClick form1)
|> Event.subscribe (\pt-> do { print $ "I was clicked at " ++ (show pt) })

所以

在我看来,功能性程序/操作系统无法自行运行

技​​术上是错误的——你可以实现无限循环——但这样做通常没有(功能)点。为什么除了某种 IO 轮询之外还需要它?以纯粹的功能方式转换值应该终止才有意义。

于 2010-08-14T15:20:38.187 回答
1

如果您的编译器识别它,您可以有无限尾递归。某些语言,例如方案,要求编译器识别尾递归并且不为其分配堆栈空间。

编辑 我并不是要不同意其他答案,但“无限”尾递归循环是处理外部世界的常见习语。下面的例子取自Real World Haskell,是成语的代表。

mainloop :: Handle -> Handle -> IO ()
mainloop inh outh = 
    do ineof <- hIsEOF inh
       if ineof
           then return ()
           else do inpStr <- hGetLine inh
                   hPutStrLn outh (map toUpper inpStr)
                   mainloop inh outh

我们本质上是把外面的世界看成一条溪流

于 2010-08-14T15:07:25.347 回答
1

函数式编程中“无限循环”的大多数(如果不是全部)使用都可以通过co-recursion建模。到目前为止,其他答案都指向一般递归,但无限制地使用递归可以说是一种糟糕的方法,因为它可能导致代码结构不佳。

纯函数式程序中的绝大多数代码应该写在整个子集中,即使用诸如结构递归或共同递归(确保终止和进展)之类的模式,而不是回退到一般递归。希望 GHC 的未来版本将包括对检测 Haskell 的某些总子集的直接支持,并对无法证明终止或进展的代码发出警告。

于 2010-08-16T04:29:03.057 回答