A procedure body can contain calls to other procedures, not least itself:
(define factorial (lambda (n) (if (= n 0) 1 (* n (factorial (- n 1))))))
This recursive procedure calculates
the factorial of a number. If the number is 0
, the answer is 1
. For any other number n
, the procedure uses itself
to calculate the factorial of n ? 1
,
multiplies that subresult by n
, and returns the product.
Mutually recursive procedures are also possible. The following predicates for evenness and oddness use each other:
相互递归:
(define is-even? (lambda (n) (if (= n 0) #t (is-odd? (- n 1))))) (define is-odd? (lambda (n) (if (= n 0) #f (is-even? (- n 1)))))
These definitions are offered here only as simple illustrations of mutual
recursion. Scheme already provides the primitive predicates even?
and odd?
.
letrec
If we wanted the above procedures as local variables, we could try to use
alet
form:
(let ((local-even? (lambda (n) (if (= n 0) #t (local-odd? (- n 1))))) (local-odd? (lambda (n) (if (= n 0) #f (local-even? (- n 1)))))) (list (local-even? 23) (local-odd? 23)))
This won’t quite work, because the occurrences of local?even?
and local?odd?
in the
initializations don’t refer to the lexical variables themselves. Changing
the let
to
a let*
won’t
work either, for while the local?even?
inside local?odd?
’s body refers to the correct procedure
value, thelocal?odd?
in local?even?
’s body still
points elsewhere.
To solve problems like this, Scheme provides the form letrec
:
(letrec ((local-even? (lambda (n) (if (= n 0) #t (local-odd? (- n 1))))) (local-odd? (lambda (n) (if (= n 0) #f (local-even? (- n 1)))))) (list (local-even? 23) (local-odd? 23)))
The lexical variables introduced by a letrec
are visible not only in theletrec
-body but also within
all the initializations. letrec
is thus tailor-made for defining
recursive and mutually recursive local procedures.
letrec专门用来定义为定义递归和相互递归的局部过程使用。
let
A recursive procedure defined using letrec
can
describe loops. Let’s say we want to display a countdown from 10
:
(letrec ((countdown (lambda (i) (if (= i 0) ‘liftoff (begin (display i) (newline) (countdown (- i 1))))))) (countdown 10))
This outputs on the console the numbers 10
down to 1
, and returns the result liftoff
.
Scheme allows a variant of let
called named let
to write this kind
of loop more compactly:
scheme有一个named let可以让let有一个名字。
(let countdown ((i 10)) (if (= i 0) ‘liftoff (begin (display i) (newline) (countdown (- i 1)))))
Note the presence of a variable identifying the loop
immediately after thelet
. This program is equivalent to the one written
with letrec
. You
may consider the named let
to be a macro (chap 8)
expanding to the letrec
form.
现在变量名countdown立即表示了整个loop,等价于上面用letrec的。
countdown
defined above is really a
recursive procedure. Scheme can define loops only through recursion. There are
no special looping or iteration constructs.
schemem只能通过递归来定义循环,没有loop或其他的循环购置。
Nevertheless, the loop as defined above is a genuine loop, in exactly the same way that other languages bill their loops. Ie, Scheme takes special care to ensure that recursion of the type used above will not generate the procedure call/return overhead.
Scheme does this by a process called tail-call elimination. If
you look closely at the countdown
procedure, you will note that when
the recursive call occurs in countdown
’s body, it is the tail
call, or the very last thing done — each invocation of countdown
either does not call itself, or
when it does, it does so as its very last act. To a Scheme implementation, this
makes the recursion indistinguishable from iteration. So go ahead, use recursion
to write loops. It’s safe.
Here’s another example of a useful tail-recursive procedure:
(define list-position (lambda (o l) (let loop ((i 0) (l l)) (if (null? l) #f (if (eqv? (car l) o) i (loop (+ i 1) (cdr l)))))))
list?position
finds the index of the first
occurrence of the object o
in the list l
. If the object is not
found in the list, the procedure returns #f
.
list-position找出list表l中对象o第一次出现的位置。
Here’s yet another tail-recursive procedure, one that reverses its argument list “in place”, ie, by mutating the contents of the existing list, and without allocating a new one:
通过改变(mutate)存在的list,不用分配内存:
(define reverse! (lambda (s) (let loop ((s s) (r ‘())) (if (null? s) r (let ((d (cdr s))) (set-cdr! s r) (loop d s))))))
(reverse!
is a useful enough procedure that
it is provided primitively in many Scheme dialects, eg, MzScheme and Guile.)
For some numerical examples of recursion (including iteration), see Appendix C.
1
2
3
4
5
6
7
8
9
10
11
12 |
scheme@(guile-user) >
(define list - reverse ... ( lambda
(ls) ... ( let
loop ((ls ls) (xs ‘())) ... ( if
(null? ls) ... xs ... ( loop
( cdr ls) ... (cons ( car
ls) xs)))))) scheme@(guile-user) >
(define ls ‘(1 2 3 4)) scheme@(guile-user) >
( list - reverse
ls) (4 3 2 1) scheme@(guile-user) >
ls (1 2 3 4) |
A special kind of iteration involves repeating the same action for each
element of a list. Scheme offers two procedures for this situation: map
andfor?each
.
The map
procedure applies a given procedure to
every element of a given list, and returns the list of the results. Eg,
(map add2 ‘(1 2 3)) => (3 4 5)
The for?each
procedure also applies a procedure
to each element in a list, but returns void. The procedure application is
done purely for any side-effects it may cause. Eg,
for-each 函数主要是为了得到函数的副作用:
(for-each display (list 1 2 3))
输出:1 2 3
如果用map会输出:
123(#<void> #<void> #<void>) (Racket下)
has the side-effect of displaying the strings (in the order they appear) on the console.
The procedures applied by map
and for?each
need not be one-argument
procedures. For example, given an n
-argument
procedure, map
takes n
lists and applies the procedure to every
set of n
of
arguments selected from across the lists. Eg,
map和for-each的存储过程参数不必是一个参数的存储过程,可以是n个。
(map cons ‘(1 2 3) ‘(10 20 30)) => ((1 . 10) (2 . 20) (3 . 30)) (map + ‘(1 2 3) ‘(10 20 30)) => (11 22 33)
参考:http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme-Z-H-8.html
http://lispor.is-programmer.com/posts/23255.html
Teach Yourself Scheme in Fixnum Days 6 recursion递归
原文:http://www.cnblogs.com/youxin/p/3547938.html