'((または...)...)のようなor-サブリストを事前にチェックして、'(... ...)に変換できるようにする必要があります。
そのための条件は、単純に次のとおりです。
(and (listp lst) (listp (first lst))
(eq (first (first lst)) 'or))
そして変圧器:
(append (remove-or (rest (first lst)))
(remove-or (rest lst)))
したがって、これにより、わずかに変更された3番目の条件ブランチを使用して関数が実行されます。
(defun remove-or (lst)
(cond ((null lst) lst)
((atom lst) lst)
((and (listp lst) (listp (first lst))
(eq (first (first lst)) 'or))
(append (remove-or (rest (first lst)))
(remove-or (rest lst))))
(t (cons (remove-or (first lst))
(remove-or (rest lst))))))
ただし、この関数は1つの特殊なケースを処理しません。リストの最初にあるor:(OR ab(または(またはcd)e))。しかし、私たちのような追加の条件ブランチがあると、変数のように機能するs((and (listp x) (eq (first x) 'or)) (remove-or (cdr x)))
も削除さor
れます:(abまたはcまたは)。
したがって、このケースは個別に処理する必要があります。たとえば、次のようになります。
(defun remove-or-head (lst)
(remove-or (if (and (listp lst) (eq (first lst) 'or))
(rest lst)
lst))
再帰関数を非表示にしてすべてをまとめるには:
(defun remove-or (lst)
(labels ((remove-or-rec (lst)
(cond ((null lst) lst)
((atom lst) lst)
((and (listp lst) (listp (first lst))
(eq (first (first lst)) 'or))
(append (remove-or-rec (rest (first lst)))
(remove-or-rec (rest lst))))
(t (cons (remove-or-rec (first lst))
(remove-or-rec (rest lst)))))))
(remove-or-rec (if (and (listp lst) (eq 'or (first lst)))
(rest lst)
lst))))