проблемы с лиспом и постройку с иттерированием - PullRequest
1 голос
/ 19 апреля 2020

Во-первых, у меня возникла эта проблема. Сгенерированный мной код перебирает не каждое слово, а весь передаваемый аргумент. Я использую do l oop для передачи информации в таблицу ha sh.

(defun set_isa (partOfSpeech &rest words)

(do ((wordVar words))
((null wordVar) nil) 

(putp partOfSpeech word-dict wordVar)
(setf wordVar (cdr wordVar))))

С этим я получаю это в результате использования trace

(set_isa 'Verb 'Talk 'Run 'jump )

1. Trace: (SET_ISA 'VERB 'TALK 'RUN 'JUMP)
1. Trace: SET_ISA ==> NIL
NIL

И когда я вызываю хеш-таблицу, он добавляет только последний переданный аргумент

#S(HASH-TABLE :TEST FASTHASH-EQL (VERB . (JUMP)))

Ответы [ 2 ]

2 голосов
/ 19 апреля 2020

Итак, способ понять, что здесь происходит, состоит в том, чтобы аннотировать ваш код, чтобы он сообщал вам, что он делает . Это может показаться античным способом отладки, но в динамическом c, разговорном языке, таком как CL, это действительно хороший подход. Вот версия вашей функции, использующая более общепринятые имена для вещей, а также использующая обычную неопределенность вместе с заглушками для отсутствующего кода, чтобы сделать его работоспособным.

(defvar *word-dict* nil)

(defun set-isa (part-of-speech &rest words)
  (do ((wtail words))
      ((null wtail) nil) 
    (putp part-of-speech *word-dict* wtail)
    (setf wtail (cdr wtail))))

(defun putp (part-of-speech dict thing)
  (format *debug-io* "~&putp: ~A ~A ~A~%" part-of-speech dict thing))

Так что теперь это можно запустить, и putp напечатает то, что получает в качестве аргументов.

 > (set-isa 'verb 'talk 'run 'jump )
putp: verb nil (talk run jump)
putp: verb nil (run jump)
putp: verb nil (jump)
nil

Таким образом, даже не имея кода, который на самом деле здесь глючит, который почти наверняка putp, вы можете решить, в чем проблема: putp заменяет любое значение, хранящееся в таблице ha sh, своим аргументом. Таким образом, единственное значение, которое заканчивается в таблице, является последним. Поэтому нам нужно исправить это, что я и сделаю позже.

Но на самом деле это не единственная проблема.

Прежде всего, вы используете do очень странным образом. , Синтаксис do явно разрешает инициализацию и пошаговое выполнение форм, поэтому вы должны использовать пошаговую форму вместо того, чтобы делать это в теле.

(defun set-isa (part-of-speech &rest words)
  (do ((wtail words (rest wtail)))
      ((null wtail) nil) 
    (putp part-of-speech *word-dict* wtail)))

Во-вторых, вы звоните putp на все хвосты вашего списка : вы, вероятно, хотите назвать его только отдельными словами. Вы можете сделать это, просто передав ему машину каждого хвоста, но, как указывает Мартин Бухманн в другом ответе, вы можете вместо этого искать в языке конструкцию, которая перебирает элементы списка. И их много, и dolist является одним из них:

(defun set-isa (part-of-speech &rest words)
  (dolist (word words)
    (putp part-of-speech *word-dict* word)))

А теперь

(set-isa 'verb 'talk 'run 'jump )
putp: verb nil talk
putp: verb nil run
putp: verb nil jump
nil

Обратите внимание, способ вызова putp не совместим с предыдущим версия: теперь она называется словами, а не хвостами списка.

Итак, наконец, давайте напишем версию putp, которая работает. Сначала я напишу очень наивную версию:

(defvar *word-dict* (make-hash-table))

(defun putp (part-of-speech dict thing)
  (let ((entries (gethash part-of-speech dict '())))
    (setf (gethash part-of-speech dict) (cons thing entries))))

И это работает, но не очень хорошо:

> (gethash 'verb *word-dict* '())
nil
nil

> (set-isa 'verb 'talk 'run 'jump )
nil

> (gethash 'verb *word-dict* '())
(jump run talk)
t

> (set-isa 'verb 'talk 'run 'jump )
nil

> (gethash 'verb *word-dict* '())
(jump run talk jump run talk)
t

Так что все в порядке, пока вы только запускаете это один раз. Что ж, мы можем сделать лучше, чем это:

  • мы можем использовать более идиоматический c способ добавления новых вещей в список, хранящийся в хеш-таблице;
  • мы можем избежать дублирующая запись, в то же время будучи более идиоматическим c.

Примерно так:

(defun putp (part-of-speech dict thing)
  (pushnew thing (gethash part-of-speech dict)))

Итак, теперь:

 > (gethash 'verb *word-dict* '())
nil
nil

> (set-isa 'verb 'talk 'run 'jump )
nil

> (gethash 'verb *word-dict* '())
(jump run talk)
t

> (set-isa 'verb 'talk 'run 'jump )
nil

> (gethash 'verb *word-dict* '())
(jump run talk)

Это намного лучше , Вы можете посмотреть push и pushnew, чтобы увидеть, что они делают.

2 голосов
/ 19 апреля 2020

Добро пожаловать на SO. Я вижу несколько проблем с нашим вопросом и надеюсь, что смогу дать вам несколько советов.

Отступ

Пожалуйста, сделайте отступ в своем коде правильно. Это приведет к более удобочитаемому коду и увеличит вероятность того, что другие могут помочь вам.

(defun set_isa (partOfSpeech &rest words)
  "Put an understandable docstring here!"
  (do ((wordVar words))
      ((null wordVar) nil) 
    (putp partOfSpeech word-dict wordVar)
    (setf wordVar (cdr wordVar))))

Вы найдете больше советов по стилю здесь . См. Также вкладку Информация для набора ссылок.

Исполняемые примеры

В нашей функции putp не определено. Поэтому я не могу запустить ваш код и посмотреть, какую именно ошибку получить, et c. Пожалуйста, дайте всегда полные примеры и четкое описание того, что вы ожидаете и что вы получаете. Часть с hash-table не совсем понятна. Откуда это взялось? Как это используется в нашем коде?

do loops

Проверьте правильность синтаксиса do и его родственников для начинающих. Если вы хотите перебрать список с помощью do, попробуйте dolist.

(dolist (item '(a b c d))
  (print item))

Используя do, вы могли бы добиться того же с помощью этой конструкции:

(do ((items '(a b c d) (rest items)))
    ((null items))
  (print (first items)))

Мне может показаться сложным сначала получить круглые скобки, но если у вас есть Логика c за ним прямо станет легче. Вам не нужна деталь setf, так как do позаботится об этом.

...