Я просто играю вокруг со схемой/шепелявостью и думал о том, как я исправлю свое собственное определение average
. Я не уверен, как сделать некоторые вещи, что я думаю, требуются все же.
Делает у кого-то есть пример определения average
? Я, кажется, не знаю достаточно о LISP для формирования веб-поиска, который возвращает результаты, которые я ищу.
Определение было бы очень простым однострочным, но, не испортив его, вы должны рассмотреть:
аргумент "rest" -- это (define (foo . xs) ...xs...)
определяет foo
как функцию, которая принимает любое количество аргументов, и они доступны в виде списка, который будет значением xs
.
length
возвращает длину списка.
apply
берет функцию и список значений и применяет функцию к этим значениям.
Когда вы получите это, вы можете пойти дальше:
см. функцию foldl
, чтобы избежать применения списка к потенциально очень большому списку (это может иметь значение в некоторых реализациях, где длина списка аргументов ограничена, но в Racket это не имеет большого значения).
обратите внимание, что в Racket есть точные рациональные числа, и вы можете использовать exact->inexact
для создания более эффективной версии с плавающей точкой.
И спойлеры:
(define (average . ns) (/ (apply + ns) (length ns)))
Сделайте его требующим один аргумент: (define (average n . ns) (/ (apply + n ns) (add1 (length ns))))
Используйте foldl
: (define (average n . ns) (/ (foldl + 0 (cons n ns)) (add1 (length ns))))
Make it use floating point: (define (average n . ns) (/ (foldl + 0.0 (cons n ns)) (add1 (length ns))))
В Scheme я предпочитаю использовать список вместо аргумента "rest", потому что аргумент rest затрудняет реализацию процедур, подобных следующим:
> (define (call-average . ns)
(average ns))
> (call-average 1 2 3) ;; => BANG!
Упаковка произвольного количества аргументов в список позволяет вам выполнять любые операции со списком над аргументами. Вы можете сделать больше с меньшим количеством синтаксиса и путаницы. Вот моя Scheme версия average
, которая принимает 'n' аргументов:
(define (average the-list)
(let loop ((count 0) (sum 0) (args the-list))
(if (not (null? args))
(loop (add1 count) (+ sum (car args)) (cdr args))
(/ sum count))))
Вот та же процедура в Common Lisp:
(defun average (the-list)
(let ((count 0) (sum 0))
(dolist (n the-list)
(incf count)
(incf sum n))
(/ sum count)))
Две версии Common Lisp:
(defun average (items)
(destructuring-bind (l . s)
(reduce (lambda (c a)
(incf (car c))
(incf (cdr c) a)
c)
items
:initial-value (cons 0 0))
(/ s l)))
(defun average (items &aux (s 0) (l 0))
(dolist (i items (/ s l))
(incf s i)
(incf l)))
В Common Lisp, похоже, вы можете:
(defun average (&rest args) (when args (/ (apply #'+ args) (length args))))
хотя я понятия не имею, доступны ли & rest
во всех реализациях Lisp. Ссылка здесь .
Помещение этого кода в GNU CLISP приводит к:
[1]> (defun average (&rest args) (when args (/ (apply #'+ args) (length args)))) AVERAGE [2]> (average 1 2 3 4 5 6) 7/2
, что составляет 3.5 (правильно).