LISP лучше понимает многоуровневые списки
Я пытаюсь лучше понять многоуровневые списки в lisp, создав функцию, в которой я удаляю все элементы, которые не являются числами, из многоуровневого списка. Сначала я пытаюсь сгладить его с помощью функции striv0, а затем проверяю, является ли первый аргумент списка числовым или нет. Однако у меня есть проблема при попытке функции
(func '(5 (5 2 (8)(7 (9)5))))
. Я получаю:COND: переменная, если не имеет значения
Код:
(DEFUN striv0 (lis)
(COND ((NULL lis) NIL)
((ATOM lis) (LIST lis))
(T (APPEND (striv0 (FIRST lis))
(striv0 (REST lis))))
))
(DEFUN func (lis)
(LET( (newList (striv0 lis)) ))
(COND ((NULL newList) NIL)
( T(IF (NUMBERP (FIRST newList))
((func(REST newList)))))))
Я считаю, что мне удалось решить эту проблему путем преобразования второй функции в первую, проверив числовые аргументы или внутренние списки, если ни одна из них не перемещается дальше по списку.
(DEFUN checkNumber (lis)
(COND ((NULL lis) NIL)
((ATOM lis) (LIST lis))
(T (if ( or(NUMBERP ( FIRST lis))(LISTP (FIRST lis)))
(APPEND ( checkNumber (FIRST lis))
( checkNumber (REST lis)))
( checkNumber (REST lis)) )
)
)
)
2 ответа
Вот некоторые построчные отзывы и некоторые подсказки:
(DEFUN func (lis) ; why is this called FUNC
; and not something useful?
; why is the variable called
; LIS and not LIST?
(LET( (newList (striv0 lis)) )) ; why is this not indented?
; why does LET not have
; body forms?
; why is the LET ending here?
(COND ((NULL newList) NIL) ; why is this not indented?
( T(IF (NUMBERP (FIRST newList)) ; why is this not indented?
((func(REST newList))))))) ; why are there so
; many parentheses?
; why is it starting
; with two parentheses?
Сначала отформатируйте свой код. Принятым соглашением является использование символов нижнего регистра и отдельных частей слова в именах символов с тире, например new-list
, Отступы используются для выравнивания форм одного уровня в одном и том же текстовом столбце. Существуют различные рецензии в стиле Lisp, вот одна из них. Вот как будет выглядеть ваш код:
(defun striv0 (lis)
(cond ((null lis) nil)
((atom lis) (list lis))
(t (append (striv0 (first lis))
(striv0 (rest lis))))))
(defun func (lis)
(let ((new-list (striv0 lis))))
(cond ((null new-list) nil)
(t (if (numberp (first new-list))
(cons (first new-list) (func (rest new-list)))))))
Хороший редактор сделает отступ для вас. Если отступ не соответствует вашим ожиданиям, вы знаете, что допустили синтаксическую ошибку. Редактор также покажет соответствующие пары скобок.
Let
принимает в качестве первого аргумента список привязок, а затем любое количество форм в его теле. Только внутри этого тела действуют привязки. Вы хотите поставить свой cond
сформировать в этом теле:
(defun func (lis)
(let ((new-list (striv0 lis)))
(cond ((null new-list) nil)
(t (if (numberp (first new-list))
((func (rest new-list))))))))
Обратите внимание, что отступ автоматически отражает структуру кода: cond
форма теперь имеет два отступа, чтобы показать, что она находится внутри let
тело. Что я на самом деле отредактировал, так это переместил закрывающую скобку let
Форма до конца.
Эта последняя форма ((func (rest new-list)))
там нет действительной формы Lisp. Форма всегда должна начинаться с оператора (который может быть символом или лямбда-формой). Я думаю, что у вас было что-то, что выглядело правильно в более ранней версии вашего вопроса: (cons (first new-list) (func (rest new-list)))
,
Я бы сейчас попробовал найти лучшие названия для этих функций. Ваш striv0
может быть условно назван flatten
, "Многоуровневые списки" обычно называются "деревьями" в Лиспе. Ваш func
таким образом можно назвать keep-numbers-from-tree
,
Я не уверен, является ли выравнивание частью ваших требований. В любом случае, я бы оставил это отдельно, так как кажется излишним делать это снова каждый раз через рекурсию. Сначала сгладьте, затем отфильтруйте числа.
Если выравнивание не является частью ваших требований, не делайте этого. При прохождении дерева в каждой точке есть только три возможности: это список (затем рекурсивный), это число (сохранить) или нечисловой атом (пропустить).