【问题标题】:Scheme using input parameter in inner function在内部函数中使用输入参数的方案
【发布时间】:2017-08-25 19:09:50
【问题描述】:

我是 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...:

谢谢

【问题讨论】:

    标签: functional-programming scheme let


    【解决方案1】:

    错误的原因是fibo 应该是一个返回整数的函数,而在内部if 的第二种情况下,您只需打印一个值(而display 返回@987654324 @,不是整数)。

    如果您正确缩进您的代码,这一点会立即清楚:

    (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!
    

    【讨论】:

    • 感谢您的详细回答,但我不允许使用when 声明...还有其他方法吗?
    • 我改了答案。
    【解决方案2】:

    分解问题。将脏副作用与生成数字的函数分开:

    (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,但它几乎与递归一样容易。

    【讨论】:

      猜你喜欢
      • 2021-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多