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就是一个例子。