(определите (среднее число …)) в Lisp

Я просто играю вокруг со схемой/шепелявостью и думал о том, как я исправлю свое собственное определение average. Я не уверен, как сделать некоторые вещи, что я думаю, требуются все же.

  • определите процедуру, которая берет произвольное число аргументов
  • считайте те аргументы
  • передайте список аргументов (+) для подведения итогов их вместе

Делает у кого-то есть пример определения average? Я, кажется, не знаю достаточно о LISP для формирования веб-поиска, который возвращает результаты, которые я ищу.

7
задан Eric Schoonover 14 July 2010 в 21:34
поделиться

4 ответа

Определение было бы очень простым однострочным, но, не испортив его, вы должны рассмотреть:

  • аргумент "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))))

11
ответ дан 6 December 2019 в 10:47
поделиться

В 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)))
1
ответ дан 6 December 2019 в 10:47
поделиться

Две версии 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)))
2
ответ дан 6 December 2019 в 10:47
поделиться

В 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 (правильно).

3
ответ дан 6 December 2019 в 10:47
поделиться