Схема с использованием входного параметра во внутренней функции

Я новичок в 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...:

Спасибо


person Noam    schedule 31.03.2017    source источник


Ответы (2)


Причина ошибки в том, что 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!
person Renzo    schedule 31.03.2017
comment
спасибо за ваш подробный ответ, но мне не разрешено использовать оператор when ... Есть ли другой способ сделать это? - person Noam; 31.03.2017
comment
Я изменил ответ. - person Renzo; 31.03.2017

Разделите проблему. Отделите грязные побочные эффекты от функции, которая генерирует числа:

(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, но это так же просто сделать с рекурсией.

person Sylwester    schedule 31.03.2017