Как я могу обнаружить тонкие ошибки синтаксиса Lisp? - PullRequest
16 голосов
/ 22 мая 2009

Я новичок, играющий с Лиспом (на самом деле, Emacs Lisp). Это очень весело, за исключением случаев, когда я снова и снова сталкиваюсь с одними и теми же синтаксическими ошибками.

Например, вот что я встречал несколько раз. У меня есть форма cond, как

(cond
 ((foo bar)
  (qux quux))
 ((or corge
      (grault warg))
  (fred)
  (t
   xyzzy)))

и предложение по умолчанию, которое возвращает xyzzy, никогда не выполняется, потому что оно фактически вложено в предыдущее предложение:

(cond
 ((foo bar)
  (qux quux))
 ((or corge
      (grault warg))
  (fred))
 (t
  xyzzy))

Мне трудно видеть такие ошибки, когда разница в отступах составляет всего один пробел. Со временем это становится легче?

У меня также возникают проблемы, когда между (неправильной) линией и линией, на которую следует сделать отступ, большое расстояние. Например, let формы с множеством сложных привязок или форма unless с длинными условными выражениями:

(defun test ()
  (unless (foo bar
               (qux quux)
               (or corge
                   (grault warg)
                   (fred))))
  xyzzy)

Оказывается, xyzzy никогда не был внутри формы unless:

(defun test ()
  (unless (foo bar
               (qux quux)
               (or corge
                   (grault warg)
                   (fred)))
    xyzzy))

Я обычно делаю отступы автоматически и использую подсветку скобок, чтобы избежать подсчета скобок. По большей части это работает как бриз, но иногда я обнаруживаю синтаксические ошибки только путем отладки. Что я могу сделать?

Ответы [ 7 ]

28 голосов
/ 22 мая 2009

Подсветка секса

Прежде всего, включите встроенную подсветку парных матчей (show-paren-mode), если это еще не сделано. Он всегда дает вам представление о том, на каком уровне отступа вы находитесь.

Есть также несколько более сложных пакетов. Например, см. ответ TJ на mic-paren. Или, хотя я не нашел это подходящим для меня, но есть режим подсветки скобок Шумахера , который выделяет каждый блок выражения разными цветами. Даже Эдвард О'Коннор имеет режим , который выделяет текущий пол.

Paredit

Используйте paredit-mode, который поможет вам написать секспс. Вы можете легко перемещаться между секциями и реструктурировать код. Кроме того, это гарантирует, что круглые скобки всегда сбалансированы. Когда я впервые попробовал это, меня очень раздражало, как Paredit ограничивает способ кодирования, но с тех пор я привык работать с ним, я стал намного продуктивнее и никогда не путаюсь с открытием и закрытием скобок.

Автоматический отступ

Используйте Emacs Starter Kit , который по умолчанию предоставляет множество полезных помощников для кодирования в Elisp, например, повторный отступ на новой строке.

ElDoc

emacs-lisp-mode имеет несколько полезных расширений. Например, я всегда использую eldoc-mode, который отображает список аргументов текущей набираемой функции или строку документации переменной в области эха. Это также поможет вам легко распознать, что вы находитесь не в том блоке.

Edebug

Я чуть не забыл упомянуть Edebug , который - как последний шанс - всегда помогает вам понять, что происходит в вашем коде.

7 голосов
/ 22 мая 2009

Вот три конкретных вещи, которые вы можете сделать, чтобы помочь выявить проблемы с синтаксисом Lisp. Со временем это станет второй натурой. Но до тех пор:

Соответствие скобок

Соответствие скобкам - самый простой способ проверить группировку. Моя любимая упаковка - mic-paren . И мне нравится эта конкретная конфигурация:

(setq paren-dont-touch-blink t)
(require 'mic-paren)
(paren-activate)
(setq paren-match-face 'highlight)
(setq paren-sexp-mode t)

Это приводит к тому, что sexp (совпадающая скобка) выделяется, когда точка находится в начале / конце sexp. Если круглые скобки не совпадают, цвет выделения будет другим - и ярче. Когда соответствующая скобка находится вне экрана, она показывает вам, как выглядит этот конец в минибуфере (и сообщает, сколько он строк).

Компиляция

Для немного более сложного метода вы можете запустить компилятор Elisp с помощью M-x compile-defun. Например, когда я скомпилировал этот простой пример:

(defun mytestfun ()
  (let ((cur (current-buffer)))
    )
  (set-buffer cur))

Я получил буфер с именем *Compile-Log*, который сказал:

Предупреждение: ссылка на свободную переменную `Дворняжка '

Это подсказало мне тот факт, что я использовал cur вне оператора let, который его определил.

Изменить уровень отступа

Если вы хотите, чтобы отступ был более заметным, вы можете настроить переменную listp-body-indent:

(setq lisp-body-indent 4) ;# default is 2

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

2 голосов
/ 22 мая 2009

«Лучший» способ написать lisp - это комбинация emacs + slime Он обеспечивает выделение скобок, табуляцию, вы можете перейти прямо к документу HyperSpec, он предоставляет имена переменных для функций (см. Ниже) и многое другое.

(defun foo (bar) ...)

Когда вы начнете печатать (foo покажет вам, что foo хочет один аргумент с именем bar. Таким образом, вы можете легко «угадать», какие аргументы принимает функция. Это особенно удобно для функций, которые не следуют соглашениям Lisp.

2 голосов
/ 22 мая 2009

Одна из простых вещей - переместить курсор в начало каждого из ваших cond условий и посмотреть, куда падает закрывающая пара.

1 голос
/ 20 августа 2013

Я вижу два подхода, которые вы можете использовать, которые могут помочь в обоих ваших примерах.

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

(cond
 (--
  --)
 (--
  --)
 (t
  --))

тогда вы можете начать заполнять детали. -- как наполнители TODO.

Ваш второй пример. Вы могли бы начать с

(defun test ()
  --)

затем заполните больше так:

(defun test ()
  (unless (--)
    --))

затем заполните больше.

Другим способом является настройка разделителей радуги, чтобы она выделяла четные уровни в одном цвете, а нечетные - в другом. Это поможет с формой cond. Это не поможет с вашим вторым примером, но если бы оно было (xyzzy) вместо xyzzy, оно бы имело.

1 голос
/ 22 мая 2009

Мне трудно видеть такие ошибки, когда разница в отступ - это только один пробел. Есть ли со временем это станет легче?

Не для меня, по крайней мере .. Это отчасти зависит от конкретного используемого вами шрифта xterm, но я считаю, что для эффективной работы мне нужен отступ в четыре пробела (да, я использую этот старый оригинальный шрифт xterm - обвинение SunOS 4), а то и два проблематично.

Я также использую подсвечивание скобок, и клавиша "%" часто используется в vi.

К сожалению, это не очень полезный ответ.

0 голосов
/ 30 апреля 2010

Чтобы добавить к ценным указателям всех остальных, я бы сказал «использовать команды перемещения на основе структуры», backward-sexp, forward-sexp и т.п. Это позволяет вам перемещаться.

...