(определить (среднее ....)) в Лиспе - PullRequest
7 голосов
/ 14 июля 2010

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

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

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

Ответы [ 5 ]

11 голосов
/ 14 июля 2010

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

  • аргумент "отдыха" - это (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))))

  • Использовать с плавающей запятой: (define (average n . ns) (/ (foldl + 0.0 (cons n ns)) (add1 (length ns))))

3 голосов
/ 14 июля 2010

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

2 голосов
/ 14 июля 2010

Две версии в 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)))
1 голос
/ 18 октября 2014

В схеме R5RS:

(define (average . numbers)  
    (/ (apply + numbers) (length numbers)))
1 голос
/ 14 июля 2010

В Схеме я предпочитаю использовать список вместо аргумента rest, поскольку аргумент rest затрудняет реализацию процедур, подобных следующим:

> (define (call-average . ns)
     (average ns))
> (call-average 1 2 3) ;; => BANG!

Упаковка произвольного количества аргументов в список позволяет выполнятьлюбая операция со списком аргументов.Вы можете сделать больше с меньшим количеством синтаксиса и путаницы.Вот моя версия схемы 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)))
...