2016-03-07 2 views
0

Я новичок в lisp, поэтому приношу свои извинения, если вы продвигаете это, это простой вопрос.Сравнение числа и объекта списка в lisp

У меня есть список:

(set ‘inventory ‘(parts 
        ((item 1001) (shoes (color brown) (size 10) (cost 20))) 
        ((item 2011) (skirt (color blue) (size 4) (cost 10))) 
        ((item 2120) (pants (color white) (size 32) (cost 30))) 
        ((item 2121) (pants (color brown) (size 34) (cost 30))))) 

Я пытаюсь написать функцию, которая просматривает список по номеру и вернуть правильный.

(findItem 1001 inventory) должен вернуться:

((item 1001) (shoes (color brown) (size 10) (cost 20))) 

Это то, что я до сих пор:

(defun findItem (q i) 
    (cond 
     ((null q) 
     nil) 
     ((null (cdr i)) 
     nil) 
     ((eq `parts (car i)) 
     (findItem q (cdr i))) 
     ((eq q (cdr (car (car i)))) 
     (car i)) 
     (T 
     (findItem q (cdr i))))) 

Все, кажется, работает, за исключением ((eq q (cdr (car (car i)))) (car i))

(cdr (car (car i))) должен вернуться (1001) или номер детали

Но th e eq не оценивает значение true, поэтому функция полностью возвращает nil.

И помощь был бы оценен

+0

Возможный дубликат [В чем разница между eq, eql, equal и equalp в Common Lisp?] (Http://stackoverflow.com/questions/547436/whats-the-difference-between-eq-eql-equal и-EQUALP-в-общем-шепелявостью) – sds

ответ

1
(cdr (car (car '((item 1001) (shoes (color brown) (size 10) (cost 20)))))) 

не работает, так как caar является item, и вы не можете взять cdr символа. Вы должны играть с ним, как это, прежде чем получить это право:

(defparameter *item* '((item 1001) (shoes (color brown) (size 10) (cost 20)))) 
(car *item*) ; ==> (item 1001) 
(caar *item*) ; ==> item 
(cdar *item*) ; ==> (1001) 

Теперь c<runs of a and d>r является abbriviation для вложенной car и cdr например (car (cdr (cdr x))) (также известный как third) может быть abbriviated caddr при чтении, как и DS от справа налево вы видите, почему.

Номера не должны быть eq, даже если они представляют одинаковое значение. Вы можете использовать equal, чтобы получить истинное значение, когда два значения выглядят одинаково, и есть =, который работает только для чисел, которые могут быть быстрее в некоторых реализациях.

set устарел. Для создания глобальных переменных используйте defparameter и используйте *earmuffs*, чтобы указать, что они являются глобальными переменными.

Я призываю вас выбрать разумные имена, поскольку q и i ничего не значит. Кроме того, использование CL coding conversion делает ваш код кратким и читаемым другими осями. Например:

(defun find-item (item-number inventory) 
    "Finds the record in inventory that has a specific item number" 
    (cond ((endp inventory) nil) 
     ...)) 
5

Как объяснен в What's the difference between eq, eql, equal, and equalp in Common Lisp?, используя eq для сравнения cons клетки неправильно. Вы должны либо использовать equal или извлечь число, т.е. заменить (cdr (car (car i))) с cadaar так что вы получите 1001 вместо (1001).

Кроме того, set осуждается, используйте setq или defparameter вместо этого.

Кроме того, вы можете использовать встроенный в find вместо:

(find 1001 (cdr inventory) :key #'cadar) 
==> ((ITEM 1001) (SHOES (COLOR BROWN) (SIZE 10) (COST 20))) 
1

Продлить на sds's answer, позвольте мне рассмотреть некоторые стилистические проблемы. Как и на любом другом языке, вы должны попытаться создать свой код, чтобы определить разумный интерфейс.

Я могу сказать, что вы можете использовать структуры или объекты, но я действительно думаю, что использование списков не обязательно является плохим. Меня беспокоит явное использование CADAR или CDR: вы делаете предположения о своем коде, который вводит связь без каких-либо особых причин. Первым шагом для разделения абстракции от реализации является определение функций доступа, таких как item-reference, row-reference (для каждой записи) и т. Д.

Если вам удастся реорганизовать ваши данные, вы с удовольствием узнаете, что вам нужно изменить только одно место, где вы определяете (item-reference x), чтобы быть (CAADDR x) (например).

Кстати, Common Lisp structures может быть реализован поверх списков, если вы предоставили как :named, так и аргумент :type list. Например, вы можете определить item структуру следующим образом:

> (defstruct (item (:type list) :named) reference) 

Затем следующий фактически построить список, в котором первый элемент указывает тип:

> (make-item :reference 300) 
=> (ITEM 300) 

defstruct также создает аксессоров:

> (item-reference *) 
300 

> (setf (item-reference **) 1010) 
1010 
0

У вас есть alist. Вы должны использовать существующие функции, которые являются built in для работы с этой структурой данных.

(defun find-item (num list) 
    (assoc num (cdr list) 
     :test (lambda (num b) 
       (equal num (second b))))) 

Обратите внимание, что я также изменил название вашей функции, чтобы больше соответствовать стилю списка.

Смежные вопросы