Хвост-рекурсивная функция уплощения в Emacs Lisp
Я изучаю On Lisp Пола Грэма и пытаюсь реализовать функции в Emacs Lisp. Один из них сглажен:
(flatten '(a (b c) ((d e) f)))
;; Returns:
(a b c d e f)
Однако по какой-то причине реализация, данная Полом Грэмом, не работает на Emacs Lisp (всегда возвращает nil):
(defun flatten (x)
(cl-labels ((rec (x acc))
(cond ((null x) acc)
((atom x) (cons x acc))
(t (rec (car x) (rec (cdr x) acc)))))
(rec x nil)))
(flatten '(1 (3)))
;; Returns:
nil
Это как-то связано с динамическим связыванием ELisp? Что не так с этим кодом?
1 ответ
Решение
Как отмечается в моем комментарии к вопросу, проблема заключается в неуместных скобках. Определение должно быть:
(defun flatten (x)
(cl-labels ((rec (x acc)
(cond ((null x) acc)
((atom x) (cons x acc))
(t (rec (car x) (rec (cdr x) acc))))))
(rec x nil)))
В оригинале, ((rec (x acc))
определяет rec
как функция, возвращающая nil
, Изменив его на ((rec (x acc)
cond
выражение становится телом rec
и затем после балансировки скобок снова, добавив закрывающую скобку после t
пункт о cond
, flatten
Функция работает как положено:
(flatten '(1 (3)))
(1 3)