在内部函数中使用输入参数的方案



我是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但使用递归几乎很容易。

相关内容

  • 没有找到相关文章

最新更新