Хобрук: Ваш путь к мастерству в программировании

Сведение древовидной структуры в Lisp

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

((atom tree)(list tree))

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

(defun flatten (tree)
(cond ((null tree)
     nil
     )
    ((atom tree)(list tree))
    (t
     (loop for a in tree appending (flatten a)))))

Объяснение было бы потрясающим, если бы кто-нибудь мог сэкономить время? Спасибо!

22.11.2013


Ответы:


1

Код довольно плохо отформатирован. В первой части вашего вопроса вообще не понятно почему

((atom tree) (list tree))

появится в любом коде Common Lisp, поскольку выглядит как попытка вызвать (atom tree), вернуть функцию и вызвать эту функцию с помощью (list tree). В контексте, при правильном форматировании, понятнее:

(defun flatten (tree)
  (cond 
   ((null tree) nil)
   ((atom tree)(list tree))
   (t (loop for a in tree
            appending (flatten a)))))

Это одно предложение в cond. В нем говорится, что если tree является атомом (который может быть символом, числом, вектором и т. д., чем угодно, кроме cons), то возвращается (list tree). Как объяснил larsmans, flatten всегда должен возвращать список, и это гарантирует, что (flatten 3), например, вернет (3). Поскольку (loop for a in tree ...) будет работать для любого tree, являющегося списком, действительно нет необходимости иметь дело для (null tree), поскольку nil/() является списком. Это определение можно упростить до:

(defun flatten (tree)
  (if (atom tree)
      (list tree)
      (loop for a in tree
            appending (flatten a)))))

В Stack Overflow есть несколько похожих вопросов, и у некоторых код почти идентичен тому, что вы опубликовали (по модулю форматирования). Друг основывал предложение на одном из них. Во всяком случае, для полноты картины вы могли бы взглянуть на:

22.11.2013
  • Спасибо за ответ. Вторая функция flatten выдает ошибку из-за лишних скобок. 08.02.2019

  • 2

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

    Точно. Постусловие flatten заключается в том, что его результатом всегда является плоский список (не "плоский список или атом"), так что рекурсивные вызовы должны обрабатывать только один тип данных.

    22.11.2013

    3

    ((atom tree)(list tree)) — это фрагмент синтаксиса, который нельзя понять сам по себе. Он относится к синтаксису cond: в культуре Лиспа он известен как пара условий. Пара cond говорит, что если выражение (atom tree) верно, то вычисляется (list tree). Затем cond завершает работу и возвращает это значение.

    Терминология пары условий неточна, поскольку в Common Lisp предложения условий являются n-арными. Они не обязательно должны быть парами. Дополнительные формы можно полностью опустить, чтобы предложения были одноэлементными элементами, что позволяет использовать cond как or:

    (cond (a) (b) (c) ...) <==> (or a b c)
    

    Здесь оценивается a. Если он возвращает true (значение, отличное от nil), то cond останавливается и возвращает значение a. В противном случае он проверяет b и так далее. Это именно то, что делает or.

    Форм может быть две и более:

    (cond (a p r s) (b t u) (c x y) ...)
    

    Если a возвращает значение true, то оцениваются p r и s, и значение s возвращается из cond. Если a дает false, то пробуется b и так далее.

    cond в основном представляет собой обобщенное or, за которое вы платите дополнительными скобками: попробуйте этот случай, или еще попробуйте тот случай и т. д.

    24.11.2013
    Новые материалы

    Расистский и сексистский робот, обученный в Интернете
    Его ИИ основан на предвзятых данных, которые создают предрассудки. Он словно переходит из одного эпизода в другой из серии Черное зеркало , а вместо этого представляет собой хронику..

    Управление состоянием в микрофронтендах
    Стратегии бесперебойного сотрудничества Микро-фронтенды — это быстро растущая тенденция в сфере фронтенда, гарантирующая, что удовольствие не ограничивается исключительно бэкэнд-системами..

    Декларативное и функциональное программирование в стиле LINQ с использованием JavaScript с использованием каррирования и генератора ...
    LINQ - одна из лучших функций C #, которая обеспечивает элегантный способ написания кода декларативного и функционального стиля, который легко читать и понимать. Благодаря таким функциям ES6,..

    Структуры данных в C ++ - Часть 1
    Реализация общих структур данных в C ++ C ++ - это расширение языка программирования C, которое поддерживает создание классов, поэтому оно известно как C с классами . Он используется для..

    Как я опубликовал свое первое приложение в App Store в 13 лет
    Как все началось Все началось три года назад летом после моего четвертого класса в начальной школе. Для меня, четвертого класса, лето кажется бесконечным, пока оно не закончится, и мой отец..

    Что в лицо
    Очерк о возвращении физиогномики и о том, почему мы должны это приветствовать. История начинается со странной науки. Р. Тора Бьорнсдоттир, Николас О. Рул. Видимость социального класса по..

    Почему шаблоны проектирования и почему нет?
    Сложность — мать всех проблем в программировании. Программное обеспечение должно быть разработано с точки зрения того, кто его поддерживает, а не того, кто его пишет, потому что программное..