Каковы лучшие практики для включения таких параметров, как аккумулятор в функции? - PullRequest
3 голосов
/ 18 февраля 2010

В последнее время я пишу больше кода на Лиспе. В частности, рекурсивные функции, которые принимают некоторые данные и создают результирующую структуру данных. Иногда кажется, что мне нужно передать два или три фрагмента информации для следующего вызова функции в дополнение к предоставленным пользователем данным. Давайте назовем эти аккумуляторы.

Как лучше организовать эти интерфейсы в моем коде?

В настоящее время я делаю что-то вроде этого:

(defun foo (user1 user2 &optional acc1 acc2 acc3)
    ;; do something
    (foo user1 user2 (cons x acc1) (cons y acc2) (cons z acc3)))

Это работает так, как мне бы хотелось, но я обеспокоен тем, что мне не нужно представлять & необязательные параметры программисту.

3 подхода, которые я несколько рассматриваю:

  • имеет функцию-обертку, которую рекомендуется использовать пользователю, которая немедленно вызывает расширенное определение.

  • использовать labels внутри функции, чья сигнатура краткая.

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

Спасибо, ребята!

Ответы [ 3 ]

4 голосов
/ 18 февраля 2010

Если вы хотите написать идиоматический Common Lisp, я бы порекомендовал цикл и переменные для итерации. Рекурсия это круто, но это всего лишь один из многих инструментов для Common Lisper. Кроме того, устранение хвостового вызова не гарантируется спецификацией Common Lisp.

Тем не менее, я бы порекомендовал подход labels, если у вас есть структура, например дерево, которая неизбежно является рекурсивной, и вы все равно не можете получать хвостовые вызовы. Необязательные аргументы позволяют деталям реализации просочиться в вызывающую сторону.

2 голосов
/ 18 февраля 2010

Ваш импульс, чтобы скрыть детали реализации от пользователя, я считаю разумным. Я не знаю общего lisp, но в Scheme вы делаете это, определяя свою вспомогательную функцию в лексической области видимости общедоступной функции.

(define (fibonacci n)
  (let fib-accum ((a 0)
                  (b 1)
                  (n n))
    (if (< n 1)
        a
        (fib-accum b (+ a b) (- n 1)))))

Выражение let определяет функцию и связывает ее с именем, видимым только в let, а затем вызывает функцию.

0 голосов
/ 18 февраля 2010

Я использовал все опции, которые вы упомянули. У всех есть свои достоинства, поэтому все сводится к личным предпочтениям.

Я пришел, чтобы использовать то, что считаю нужным. Если я думаю, что сохранение аккумуляторов &optional в API может иметь смысл для пользователя, я оставляю это в поле. Например, в функции, подобной reduce, аккумулятор может использоваться пользователем для предоставления начального значения , В противном случае я буду часто переписывать его в виде loop, do или iter (из библиотеки итераций), если это имеет смысл воспринимать как таковое. Иногда также используется помощник labels.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...