Functional programming 如何在函数语言中实现循环

Functional programming 如何在函数语言中实现循环,functional-programming,scheme,lisp,paradigms,purely-functional,Functional Programming,Scheme,Lisp,Paradigms,Purely Functional,在函数式语言中,例如Scheme或Lisp中存在for和for all循环。然而,循环的需要变异,因为每次迭代都不是新的堆栈帧。由于这些语言中没有明确的变异,这些函数式语言如何实现各自的迭代循环?Scheme循环是在后台使用递归实现的;诸如的构造只是转换为递归过程的宏。例如,此循环使用典型的过程语言: void打印(int n){ 对于(int i=0;i

在函数式语言中,例如
Scheme
Lisp
中存在
for
for all
循环。然而,循环的
需要变异,因为每次迭代都不是新的堆栈帧。由于这些语言中没有明确的变异,这些函数式语言如何实现各自的迭代循环?

Scheme循环是在后台使用递归实现的;诸如的构造只是转换为递归过程的宏。例如,此循环使用典型的过程语言:

void打印(int n){
对于(int i=0;i
。。。相当于方案中的以下程序;在这里,您可以看到循环的每个部分(初始化、退出条件、增量、主体)都有一个对应的表达式:

(define (print n)
  (define (loop i)     ; helper procedure, a "named let" would be better
    (when (< i n)      ; exit condition, if this is false the recursion ends
      (display i)      ; body
      (loop (+ i 1)))) ; increment
  (loop 0))            ; initialization
(定义(打印n)
(define(loop i);helper过程,“named let”更好
(当(

你注意到调用递归后没有什么事情可做了吗?编译器非常聪明,可以使用单堆栈帧对此进行优化,有效地使其与
循环的一样高效-有关更多详细信息,请阅读。为了澄清,在方案中,突变是明确可用的,请阅读说明。

这个问题实际上是两个问题,也是一个困惑

方案中的迭代 在该方案中,迭代是通过递归实现的,同时语言的语义要求某些类型的递归不消耗内存,特别是尾部递归。注意,这并不意味着突变。例如,这里有一个
while
环路i球拍的定义

(define-syntax-rule (while test form ...)
  (let loop ([val test])
    (if val
        (begin
          form ...
          (loop test))
        (void))))
如您所见,对
循环的递归调用处于尾部位置,因此不消耗内存

传统Lisps中的迭代 传统的Lisp不要求尾部调用消除,因此需要迭代构造:这些构造通常由语言提供,但通常可以用较低级别的构造实现,例如GO TO。以下是Common Lisp中
while
的定义,该定义实现了这一点:

(defmacro while (test &body forms)
  (let ((lname (make-symbol "LOOP")))
    `(tagbody
      ,lname
      (if ,test
          (progn
            ,@forms
            (go ,lname))))))
关于突变的困惑
Scheme和传统的Lisp都提供了变异运算符:您可能认为它们都不是纯函数语言。Scheme更接近于一个,但仍然不是很接近。

因为变异在这些语言中不明确可用:在纯语言中该部分是错误的变异通过状态传递模拟,与尾部递归模拟的循环协同工作。Prolog就是一个例子。