- 我想知道:可以在函数式编程中完成无限循环吗?
例子:使用windows API获取windows消息时,通常是循环实现的。
我知道可以创建一个无限期地继续递归的函数。我希望这会导致堆栈溢出。
无限循环是函数式编程的错误思维方式吗?
是操作系统的接口还是硬件的问题?
在我看来,功能性程序/操作系统无法自行运行
我有一点编写函数式程序的经验,但这一直困扰着我。请分享您对这些问题的想法/见解
例子:使用windows API获取windows消息时,通常是循环实现的。
我知道可以创建一个无限期地继续递归的函数。我希望这会导致堆栈溢出。
无限循环是函数式编程的错误思维方式吗?
是操作系统的接口还是硬件的问题?
在我看来,功能性程序/操作系统无法自行运行
我有一点编写函数式程序的经验,但这一直困扰着我。请分享您对这些问题的想法/见解
如果你使用尾递归,你实际上有一个迭代,就像一个 for/while 循环。因此,我猜你可以有一个无限循环而不会导致堆栈溢出。
对于您的问题:“无限循环是函数式编程的错误思维方式吗?” 也许这会有所帮助: - F# 中的 While 或 Tail Recursion,什么时候使用?
正如其他人所发布的那样,通过尾递归可以实现无限循环。
例如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 轮询之外还需要它?以纯粹的功能方式转换值应该终止才有意义。
如果您的编译器识别它,您可以有无限尾递归。某些语言,例如方案,要求编译器识别尾递归并且不为其分配堆栈空间。
编辑 我并不是要不同意其他答案,但“无限”尾递归循环是处理外部世界的常见习语。下面的例子取自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
我们本质上是把外面的世界看成一条溪流。
函数式编程中“无限循环”的大多数(如果不是全部)使用都可以通过co-recursion建模。到目前为止,其他答案都指向一般递归,但无限制地使用递归可以说是一种糟糕的方法,因为它可能导致代码结构不佳。
纯函数式程序中的绝大多数代码应该写在整个子集中,即使用诸如结构递归或共同递归(确保终止和进展)之类的模式,而不是回退到一般递归。希望 GHC 的未来版本将包括对检测 Haskell 的某些总子集的直接支持,并对无法证明终止或进展的代码发出警告。