Динамические переменные в выражении Lisp Case - PullRequest
4 голосов
/ 18 декабря 2010

Я написал этот фрагмент кода на обычном языке (игнорируйте ... поскольку вставлять эту часть здесь бессмысленно).

(case turn 
   (*red-player* ...)
   (*black-player* ...)
   (otherwise ...))

red-player и black-player - это переменные, которые были определены с помощью оператора defvar, чтобы «смоделировать» оператор #define в C.

(defvar *red-player* 'r)
(defvar *black-player* 'b)

Как вы можете себе представить, когда переменная turn получает либо значение *red-player* ('r), либо значение *black-player* (' b), оператор case не работает должным образом, как ожидается этот ход содержит *red-player* как литерал, а не содержимое переменной *red-player*.

Я знаю, что могу легко это исправить, используя операторы cond или if + equal, так как там оценивается содержимое переменной, но мне любопытно. Может быть, есть способ создать что-то вроде макроса Си в Лиспе, или есть какой-то особый оператор case, который позволяет использовать только переменные вместо литералов.

Заранее спасибо!

Ответы [ 3 ]

5 голосов
/ 19 декабря 2010

Вы можете ввести значение выражений в свои формы с помощью оценки времени чтения

CL-USER 18 > (defvar *foo* 'a)
*FOO*

CL-USER 19 > (defvar *bar* 'b)
*BAR*

CL-USER 20 > '(case some-var (#.*foo* 1) (#.*bar* 2))
(CASE SOME-VAR (A 1) (B 2))

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

Обратите внимание также, что идея о том, что существует переменная с описательным именем для некоторого внутреннего значения, например, не нужна в Лиспе:

dashedline = 4
drawLine(4,4,100,100,dashedline)

будет в Лиспе

(draw-line 4 4 100 100 :dashed-line)

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

4 голосов
/ 18 декабря 2010

Короткий ответ: «Да, вы можете сделать это, вроде».

И более длинный ответ включает в себя использование defmacro для создания собственной версии case, скажем mycase, которая будет возвращать обычную case форму.Определенный вами макрос будет оценивать заголовок каждого списка в теле дела.

Вы бы позвонили:

(mycase turn
     (*red* ...)
     (*black* ...)
     (otherwise ...))

, который вернул бы

(case turn
   ((r) ...)
   ((b) ...)
   (otherwise ...))

в оценщик,Возвращенная форма case будет затем оценена так, как вы хотите.

Тогда вы сможете продолжить программирование в стиле c-esque до ужаса от шуток повсюду!Беспроигрышный?

2 голосов
/ 18 декабря 2010

Вы можете злоупотреблять Лиспом так, как вам нравится. Он такой гибкий, в отличие от С.

Это не всегда как использование, которое вы используете. Зачем торопить Лисп?

Попробуйте этот подход:

 (defvar *turn* nil)

 (cond
      ((eq *turn* 'red) 
        ...
        (setq *turn* 'black)))
      ((eq *turn* 'black) 
        ...
        (setq *turn* 'red)))
      (t
        .......))
...