LINUX.ORG.RU

Инициализация property list

 ,


0

1

Инициализирую plist как nil.

(setq pl nil)
(lax-plist-put pl "a" '(1 2))
pl
pl - nil
Т.е. элемент не добавился.

Инициализирую plist как (nil nil).

(setq pl '(nil nil))
(lax-plist-put pl "a" '(1 2))
pl
pl - (nil nil «a» (1 2))

Я понимаю, что nil - не совсем лист (хотя формально равно '()) и такой код не работает:

(setq pl nil)
(add-to-list pl '("a" '(1 2)))

Так как можно создать plist чтобы потом наполнять его, не делая при этом предположений относительно того есть там элементы или нет?

ну да, как-то так.
можно сделать (setq pl (list nil))
и потом когда надо из листа брать что-то всегда брать из (cdr pl)
а первый элемент всегда лежать будет в виде nil'а

Bad_ptr ★★★★★
()

Готовой функции не знаю, но можно использовать такой макрос:

(defmacro push-pl (pl key val)
  `(if (equal 'nil ,pl)
       (setq ,pl (list ,key ,val))
     (lax-plist-put ,pl ,key ,val)))
Norgat ★★★★★
()

Проблема в том, что значение nil в Elisp - иммутабельное. Поэтому нельзя создать лист (nil) и потом изменять его, т.е., добавлять свойства. Не помню, где нагуглил это, но, столкнувшись, сам был в шоке, что нельзя изменять свойства нулевого списка. Используй лучше association lists.

iVS ★★★★★
()
Последнее исправление: iVS (всего исправлений: 1)

(setq pl '(nil nil))

так делать не надо, вроде.
если данные меняться будут нужно всегда создавать новый лист (list nil nil).
А заквоченные списки — только для статических данных, т.к. они могут шариться для экономии памяти и т.д. Во всяком случае в sbcl так можно получить непонятные глюки. хотя тут елисп... не знаю, но лучше не привыкать к плохому :)

Bad_ptr ★★★★★
()
Последнее исправление: Bad_ptr (всего исправлений: 1)

другой вариант — чтобы функция возвращала список и тогда на любое изменение списка нужно будет делать присваивание

(setq pl (set-parameters pl param-name param-value))
(defun set-parameters (pl param-name param-value)
  (if (null pl)
     (list param-name param-value)
     (cons param-name (cons param-value pl))))

Bad_ptr ★★★★★
()
Последнее исправление: Bad_ptr (всего исправлений: 1)
Ответ на: комментарий от Norgat

Готовой функции не знаю, но можно использовать такой макрос:

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

Kostafey
() автор топика
Ответ на: комментарий от iVS

Проблема в том, что значение nil в Elisp - иммутабельное.

Начинаю понимать.

Используй лучше association lists.

Да вот колебался с выбором. Просмотрел http://www.emacswiki.org/emacs/AlistVsPlist в alist не понравилось, что нельзя по-хорошему менять список, только добавлять элемент выше (а в моем случае это актуально).

Kostafey
() автор топика
Ответ на: комментарий от Kostafey

Можно почти аналогичног и функцией сделать, просто я думал что я что-то не понимаю в этой жизни...

Пример можно? Без квотирования аргумента функции только (иначе зачем там функция?). Ибо, как я понимаю, в функцию plist передаётся по значению, а нам нужно имя символа, чтобы подменить его содержимое если он nil.

Norgat ★★★★★
()
Ответ на: комментарий от Bad_ptr

ну дак мы же не видим исходник функции: lax-plist-put

C-h f lax-plist-put

lax-plist-put is a built-in function in `C source code'.

А оно точно надо приводить исходник? ;)

Kostafey
() автор топика
Ответ на: комментарий от Kostafey

Я имел ввиду in place замену pl. То, что можно в функциональном стиле написать и получить многословную конструкцию это-то очевидно было :)

Norgat ★★★★★
()
Ответ на: комментарий от Norgat

То, что можно в функциональном стиле написать и получить многословную конструкцию это-то очевидно было :)

Больше велосипедов хороших и разных! ;)

Да, пожалуй использовать макрос push-pl - лучшее решение, спасибо.

Kostafey
() автор топика
Ответ на: комментарий от Bad_ptr

хотя тут полчуется иф лишний, просто отсавить:

(cons param-name (cons param-value pl) одно и тоже получается

Нет, вообще-то это не совсем то что надо получается. if нужен для того, чтобы дублирующие элементы не возникали. Т.е. в else части должно быть:

(lax-plist-put pl param-name param-value)
Kostafey
() автор топика
Ответ на: комментарий от Kostafey

в alist не понравилось, что нельзя по-хорошему менять список, только добавлять элемент выше

Так и есть. Для изменения значений предназначен vector, но он имеет неизменную длину.

iVS ★★★★★
()
Ответ на: комментарий от iVS

Для accotiation list посмотри assoc, rassoc функции, может быть, будет достаточно.

iVS ★★★★★
()
Ответ на: комментарий от Kostafey

Да, пожалуй использовать макрос push-pl - лучшее решение, спасибо.

Тут одна проблема этого макроса дошла до меня:

(setq pl '())

(defun tt (pl)
  (push-pl pl "g" 2))

(tt pl)

и pl тут будет nil. Так что push-pl ограничен только зоной видимости объявления (setq pl ...). Если нужно выйти за неё, то придётся протаскивать значения pl в функциональном стиле через возвращаемые функциями значения.

Но, если pl будет глобальной переменной, то всё ок должно быть (если не перекрывать её локальной переменной).

P.S. наверно самым простым, в этой ситуации, будет использование (setq pl (list nil nil)). Иначе количество костылей или ограничений будет слишком велико.

Norgat ★★★★★
()
Последнее исправление: Norgat (всего исправлений: 3)
lax-plist-put is a built-in function in `C source code'.

...
The new plist is returned; 
use `(setq x (lax-plist-put x prop val))' to be sure to use the new value.
...
Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Ну и еще строчка (не успел подредактировать):

The PLIST is modified by side effects.

Вот эти три строчки должны все объяснить. :)

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)
Ответ на: комментарий от Zubok

Вот эти три строчки должны все объяснить. :)

Сейчас сделал сам себе facepalm.png. ;)
Оказывается достаточно было посмотреть внимательно матчасть. :))
Спасибо!

Kostafey
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.