我是Scheme和函数式编程的新手。
作为练习的一部分,我尝试实现一个函数,该函数n
并逐行打印斐波那契数字n
问题是当程序到达递归调用时,它无法识别n
,因此我收到合同违规错误。
通过探索网络,我认为我需要以某种方式使用let
功能,但我不确定如何。
代码如下:
(define fibo (lambda (n)
(if (= n 1)
1
(if (= n 2)
(begin
(display "1")
(newline)
1)
(begin
(display
(+ (fibo (- n 1)) (fibo (- n 2))))
)))))
我得到的错误是:
contract violation
expected: number?
given: #<void>
argument position: 1st
other arguments...:
谢谢
错误的原因是fibo
应该是一个返回整数的函数,而在内部if
的第二种情况下,您只需打印一个值(并且display
返回#<void>
,这不是整数(。
如果您正确缩进代码,这一点会立即清楚:
(define fibo
(lambda (n)
(if (= n 1)
1
(if (= n 2)
(begin
(display "1")
(newline)
1)
(begin
(display (+ (fibo (- n 1)) (fibo (- n 2)))))))))
您可以注意到,第二个if
的第一个分支以 1
结尾,返回,而第二个分支返回display
的结果。
如果删除各种display
调用(由于打印的值包含许多重复项,因此没有用(,则该函数将生成正确的结果:
(define fibo
(lambda (n)
(if (= n 1)
1
(if (= n 2)
1
(+ (fibo (- n 1)) (fibo (- n 2)))))))
请注意,它可以以更简洁的形式重写:
(define fibo
(lambda (n)
(if (<= n 2)
1
(+ (fibo (- n 1)) (fibo (- n 2))))))
最后,如果你想显示斐波那契的所有数字,直到某个值,你可以定义一个函数,如下:
(define display-all-fibo
(lambda (n)
(define display-fibo
(lambda (i)
(if (<= i n)
(begin
(display (fibo i))
(newline)
(display-fibo (+ i 1)))
(display "Done!"))))
(display-fibo 1)))
(display-all-fibo 9)
1
1
2
3
5
8
13
21
34
Done!
把问题分开。将脏副作用与生成数字的函数分开:
(define (fib-list from to)
...)
(fib-list 10 20)
; ==> (55 89 144 233 377 610 987 1597 2584 4181 6765)
然后很容易制作一个打印所述列表的函数:
(define (print-fib-list from to)
(for-each displayln (fib-list from to)))
这使用for-each
但使用递归几乎很容易。