Цикл бесконечен, так как вы ничего не повторяете, вы несколько раз применяете action
, но если он не мутирует элемент, как это делает pprint
, тогда, если результат test
отрицательным, то он останется таким, и список не будет пустым, даже если удаление сработало при вашей попытке.
УДАЛИТЬ является деструктивной функцией. В Common Lisp деструктивным операциям разрешено уничтожать их аргументы. Вы должны отказаться от любых ссылок на аргумент и использовать только возвращаемое значение. После завершения операции нет никаких гарантий относительно состояния аргумента. В частности, это может не иметь никакого эффекта, поскольку реализациям также разрешается действовать идентично неразрушающему аналогу, но обычно составные части последовательности будут повторно собираться некоторым трудным для прогнозирования способом. В вашем примере вы также уничтожаете литерал с неопределенным поведением, которого следует избегать.
Как правило, лучше всего рассматривать списки в Common Lisp как неизменяемые и разрушительные операции как микрооптимизацию, которую следует использовать только тогда, когда вы уверены, что они ничего не сломают. Для этой проблемы вы можете перебрать список, используя LOOP, собирая список результатов с условным значением COLLECT
. См. Главу LOOP в PCL .