LINUX.ORG.RU

[CL] defun и setf


0

0

Первые сто страниц ANSI Common Lisp наивно полагал, что setf — это присваивание какому-то символу вычисленного второго аргумента, а defun — это просто специализированная обертка вокруг setf для создания функций. Т.е. ассоциирование с символом какого-то кода. Но на сотой странице Грэм производит пробный взрез мозга:

By making the first argument to defun a list of the form (setf f), you define what happens when the first argument to setf is a call to f. The following pair of functions defines primo as a synonym for car:

 (defun primo (1st ) (car 1st))

 (defun (setf primo) (val 1st)
    (setf (car 1st) val)) 
In the definition of a function whose name is of the form (setf f), the first parameter represents the new value, and the remaining parameters represent arguments to f. Now any setf of primo will be a call to the latter function above:
> (let ((x (list 'a 'b 'c)))
       (setf (primo x) 480)
      x)
(480 B C)

На ум приходит только operator= и что-то вроде operator* из C++. Но зачем это нужно? Ведь в (setf (primo x) 480), где primo равнозначно car, car и вернет ссылку, которой можно присвоить. Что Я Думаю Не Так?

Аналог car приведен лишь в качестве примера механизма определения так называаемых setfable places. Полезно если, например, ты решишь создать собственный контейнерный тип. У тебя будет getter для получения значения поля которому, к тому же, можно будет присваивать с помощью setf. Удобно для единообразия, которого в CL и так не хватает.

satanic-mechanic
()

car возвращает не ссылку на первый элемент, а сам первый элемент. В лиспе нет таких же ссылок, как T& в C++.

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

car возвращает не ссылку на первый элемент, а сам первый элемент

Тогда я не понимаю.

(defun (setf primo) (val 1st)
    (setf (car 1st) val))  
setf (car lst) — тогда car возвращает само значение, которое менять бессмысленно. А если возвращается ссылка, то тогда зачем вообще нужна эта форма с setf?

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

Тогда я не понимаю.

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

place n. 1. a form which is suitable for use as a generalized reference. 2. the conceptual location referred to by such a place[1].

В зависимости от того, какая у тебя используется форма, макрос setf по-разному раскрывается.

[1]> (macroexpand-1 '(setf (car x) 1)) (SYSTEM::%RPLACA X 1) ; T [2]> (macroexpand-1 '(setf (aref x) 1)) (LET* ((#:G8627 X) (#:G8628 1)) (SYSTEM::STORE #:G8627 #:G8628)) ; T [3]> (macroexpand-1 '(setf (aref x 1) 1)) (LET* ((#:G8629 X) (#:G8630 1) (#:G8631 1)) (SYSTEM::STORE #:G8629 #:G8630 #:G8631)) ; T

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

Чертов, лоркод :(

[code] [1]> (macroexpand-1 '(setf (car x) 1)) (SYSTEM::%RPLACA X 1) ; T [2]> (macroexpand-1 '(setf (aref x) 1)) (LET* ((#:G8627 X) (#:G8628 1)) (SYSTEM::STORE #:G8627 #:G8628)) ; T [3]> (macroexpand-1 '(setf (aref x 1) 1)) (LET* ((#:G8629 X) (#:G8630 1) (#:G8631 1)) (SYSTEM::STORE #:G8629 #:G8630 #:G8631)) ; T

[/code]

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

Да, твою же ж мать.


[1]> (macroexpand-1 '(setf (car x) 1))
(SYSTEM::%RPLACA X 1) ;
T
[2]> (macroexpand-1 '(setf (aref x) 1))
(LET* ((#:G8627 X) (#:G8628 1)) (SYSTEM::STORE #:G8627 #:G8628)) ;
T
[3]> (macroexpand-1 '(setf (aref x 1) 1))
(LET* ((#:G8629 X) (#:G8630 1) (#:G8631 1)) (SYSTEM::STORE #:G8629 #:G8630 #:G8631)) ;
T

anonymous
()
Ответ на: комментарий от j-a-t-a

> Я думал, лисп более единообразен

Более единообразный лисп - это схема.

anonymous
()
Ответ на: комментарий от Love5an

И как это к SETF, который как раз таки униформенный доступ предоставляет, относится?

Меня очень удивило, что в присваивании такая непростая кухня. Еще больше удивила приведенная аноном цитата насчет places. И, в общем, я до сих пор слабо себе представляю, почему car не может возвращать ссылку на элемент, а не его значение, и в результате приходится такой огород городить. Так что пройду ACL, буду стандарт читать.

j-a-t-a
() автор топика
Ответ на: комментарий от j-a-t-a

я до сих пор слабо себе представляю, почему car не может возвращать ссылку на элемент

Потому что в лиспе нет ссылок.

В нем абсолютно такая же ситуация, как и в других высокоуровневых языках.

Сравни

a[10]             (aref a 10)             взять 10ый элемент в массиве
a[10] = 20        (setf (aref a 10) 20)   присвоить значение элементу

или тоже самое для хэш таблиц

a["foo"]          (gethash "foo" a)
a["foo"] = "bar"  (setf (gethash "foo" a) "bar")

Т.е. абсолютно тоже самое - только немного другая запись. Но она и более универсальная, потому что ты можешь указать свою (произвольную) форму для setf - это что-то вроде переопределения оператора присваивания. Собственно в примере это и делается, просто в весьма необычной форме. (defun (setf form) ...) насколько я знаю равнозначна (defsetf form ...), в более сложных случаях используется макрос define-setf-expander.

Вот почитай в hyperspec

http://www.lispworks.com/documentation/lw50/CLHS/Body/m_defset.htm#defsetf

http://www.lispworks.com/documentation/lw50/CLHS/Body/m_defi_3.htm#define-set...

Так что пройду ACL, буду стандарт читать

На самом деле ACL не самая лучшая книга для начинающих по лиспу, учитывая, что её автор не сильно любит CL. Лучше на мой взгляд сначала прочесть PCL.

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

Потому что в лиспе нет ссылок.

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

One of secrets to understanding Lisp is to realize that variables have values in the same way that lists have elements. As conses have pointers to their elements, variables have pointers to their values.

Поэтому я и задал вопрос насчет car.

j-a-t-a
() автор топика
Ответ на: комментарий от anonymous

И да, ACL на самом деле прекрасен. Знаю, что всех достали разговоры про Грэма, но пишет он замечательно, очень четко и по делу. PCL начинал читать, но по сравнению с ACL как-то очень слабенько (ИМХО). Хотя его роль в популяризации трудно недооценить.

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