SCHEME Изменяемые функции

Последние несколько месяцев я занимался самообучением Scheme R5RS и только начал изучать изменяемые функции. Я сделал пару таких функций, но, похоже, нашел свою ошибку в этой.

(define (lst-functions)
  (let ((lst '()))
    (define (sum lst)     
      (cond ((null? lst) 0)
            (else
             (+ (car lst) (sum (cdr lst))))))
    (define (length? lst)
      (cond ((null? lst) 0)
            (else
             (+ 1 (length? (cdr lst))))))
    (define (average)
      (/ (sum lst) (length? lst)))
    (define (insert x)
      (set! lst (cons x lst)))
    (lambda (function)
      (cond ((eq? function 'sum) sum)
            ((eq? function 'length) length?)
            ((eq? function 'average) average)
            ((eq? function 'insert) insert)
            (else
             'undefined)))))

(define func (lst-functions))
((func 'insert) 2)
((func 'average))

person Sara    schedule 22.11.2016    source источник


Ответы (2)


Вы не объявляете параметр lst в процедурах, которые его используют, но вы передаете его при их вызове. Я отметил строки, которые были изменены, попробуйте следующее:

(define (lst-functions)
  (let ((lst '()))
    (define (sum lst)     ; modified
      (cond ((null? lst) 0)
            (else
             (+ (car lst) (sum (cdr lst))))))
    (define (length? lst) ; modified
      (cond ((null? lst) 0)
            (else
             (+ 1 (length? (cdr lst))))))
    (define (average)
      (/ (sum lst) (length? lst)))
    (define (insert x)
      (set! lst (cons x lst)))
    (lambda (function)
      (cond ((eq? function 'sum) (lambda () (sum lst)))        ; modified
            ((eq? function 'length) (lambda () (length? lst))) ; modified
            ((eq? function 'average) average)
            ((eq? function 'insert) insert)
            (else
             'undefined)))))

Теперь он работает так, как ожидалось:

(define func (lst-functions))
((func 'insert) 2)

((func 'average)) 
=> 2
((func 'sum))
=> 2
((func 'length))
=> 1
person Óscar López    schedule 22.11.2016

Некоторые из ваших функций рекурсивны, но определены без аргументов. Таким образом, (sum (cdr lst)) не должен работать, так как sum использует lst. Вы можете сделать это, определив помощника:

(define (sum-rec lst)
  (if (null? lst)
      0
      (+ (car lst) (sum-rec (cdr lst)))))

Или, возможно, с аккумулятором:

(define (sum-iter lst acc)
  (if (null? lst)
      acc
      (sum-iter (cdr lst) (+ (car lst) acc)))

Ваш sum, конечно же, использовал бы его, передавая lst:

(define (sum)
  (sum-iter lst 0))

Или вы можете просто частично применить их к драйверу следующим образом:

(lambda (function)
      (cond ((eq? function 'sum) (lambda () (sum-iter lst))
            ...))

Примечание. length? — функция со странным названием. Знак вопроса в конце имени обычно зарезервирован для функций, которые возвращают истинное или ложное значение, и это явно возвращает число.

person Sylwester    schedule 22.11.2016
comment
Спасибо за подсказку с длиной? Я не хотел использовать встроенную функцию длины, поэтому здесь есть ?. Я буду иметь в виду этот факт. - person Sara; 22.11.2016