2013-09-03 5 views
0

Следующая функция, которая суммирует 1/2^n, пока не достигнет 0. Может ли кто-нибудь сказать мне, нужна ли мне инструкция else, и как упорядочить круглые скобки, чтобы ошибок компиляции не было?Схема: рекурсивная функция zeno

(define (zeno n) 
    (if (= n 0) 
     (+ 0) 
     (else 
     ((+ (/ 1 (expt 2 n))) 
     ((zeno(- n 1))))))) 
+0

Не работает ли это только из-за ошибки округления FP? –

ответ

3

У меня есть шляпа, мой чай и нечего делать какое-то время на работе. Вы знаете, в какое время.

[доны code-review шляпа]

Во-первых, если у вас properly indented свой код, он будет читать

(define (zeno n) 
    (if (= n 0) 
     (+ 0) 
     (else 
     ((+ (/ 1 (expt 2 n))) 
      ((zeno (- n 1))))))) 

if на схеме не нравится if/then/else конструкцию C подобных языкам. Это на самом деле ternary operator. Другими словами, else не имеет смысла в этом контексте.

(define (zeno n) 
    (if (= n 0) 
     (+ 0) 
     ((+ (/ 1 (expt 2 n))) 
     ((zeno (- n 1))))))) 

Вам не нужно использовать + возвратить число; числа самооценки.

(define (zeno n) 
    (if (= n 0) 
     0 
     ((+ (/ 1 (expt 2 n))) 
     ((zeno (- n 1))))))) 

Если у вас есть выражение, как (foo bar baz), это обычно означает

"Вызов функции с аргументами foobar и baz"

Вы не можете просто добавить дополнительные скобки, как вам заблагорассудится; они меняют смысл выражения. Например, ((foo) (bar baz)) означает

«Вызов функции foo без аргументов, и вызвать его результат с результатом вызова bar с аргументом baz»

Другими словами,

... 
((+ (/ 1 (expt 2 n))) 
((zeno (- n 1)))))) 

что вы говорите, и почти наверняка это не значит, вот

«Вызвать функцию (+ (/ 1 (expt 2 n))) с результатом вызова результата вызова zeno с аргументом (- n 1) без аргументов."

То, что вы, кажется, имею в виду

„Добавить 1 деленной на 2^n в результате вызова zeno с один меньше, чем n

Это означает, что то, что вы должны сказать, is

(define (zeno n) 
    (if (= n 0) 
     0 
     (+ (/ 1 (expt 2 n)) 
      (zeno (- n 1))))) 
1

У вас есть несколько синтаксических ошибок (ошибочная скобка, в основном), а if форма не использует else - не поймите меня неправильно, это делает иметь «еще» часть, это просто вы не должны явно писать else, чтобы он работал. Я считаю, что это то, к чему вы стремились:

(define (zeno n) 
    (if (= n 0) 
     0 
     (+ (/ 1 (expt 2 n)) 
     (zeno (- n 1))))) 
1

Для совершенно другого подхода для вычисления суммирования используется явный цикл do. Он избегает использования expt (по дизайну).

(define (zeno n) 
    (do ((n n (- n 1)) 
     (sum 0 (+ sum frac)) 
     (frac 1/2 (/ frac 2))) 
     ((zero? n) sum))) 

Это может или не может быть более удобным для чтения при записи в его эквивалент имени let форма:

(define (zeno n) 
    (let loop ((n n) 
      (sum 0) 
      (frac 1/2)) 
    (if (zero? n) 
     sum 
     (loop (- n 1) (+ sum frac) (/ frac 2))))) 

Для еще более совершенно другой подход, вы можете использовать SRFI 41 потоки:

(define zeno 
    (let ((frac-stream (stream-iterate (cut/<> 2) 1/2))) 
    (lambda (n) 
     (stream-fold + 0 (stream-take n frac-stream))))) 

(Для приведенного выше фрагмента также требуется SRFI 26 должен быть загружен, в дополнение к SRFI 41.)


Еще еще более совершенно другой подход: использовать только в замкнутом виде раствора! (Спасибо, WorBlux.)

(define (zeno n) 
    (- 1 (/ (expt 2 n)))) 
+0

Не можете ли вы просто аналитически упростить функцию для (пусть ((base (expt 2 n))) (/ (- base 1) base))? – WorBlux

+0

@WorBlux Ну, да, это справедливая точка. : -P (я отредактировал свой ответ, чтобы включить более простую форму вашего предлагаемого решения.) –