gpt4 book ai didi

lisp - 关于onlisp中的广义变量

转载 作者:太空宇宙 更新时间:2023-11-03 18:42:36 25 4
gpt4 key购买 nike

我不太清楚这里是怎么回事,文中的宏观例子。基本上,不熟悉如何使用 get-setf-method,一个内置宏(也许是函数?)。具体来说,get-setf-method 的某些返回值为 nil 的情况如何?例如 (get-setf-method 'x)

NIL ;
NIL ;
(#:NEW-3069) ;
(SETQ X #:NEW-3069) ;
X

以及为什么这个示例代码首先将第五个返回值设置为第二个返回值,以进行初始化?最后,它如何处理在表达式中设置变量的顺序,例如 (aref ar (incf i)

(get-setf-method '(aref ar (incf i)))

(#:G3070 #:G3071) ;
(AR (INCF I)) ;
(#:G3072) ;
(SYSTEM::STORE #:G3070 #:G3071 #:G3072) ;
(AREF #:G3070 #:G3071)

宏的定义如下:

(defmacro sortf (op &rest places)
(let* ((meths (mapcar #'(lambda (p)
(multiple-value-list
(get-setf-method p)))
places))
(temps (apply #'append (mapcar #'third meths))))
`(let* ,(mapcar #'list
(mapcan #'(lambda (m)
(append (first m)
(third m)))
meths)
(mapcan #'(lambda (m)
(append (second m)
(list (fifth m))))
meths))
,@(mapcon #'(lambda (rest)
(mapcar
#'(lambda (arg)
`(unless (,op ,(car rest) ,arg)
(rotatef ,(car rest) ,arg)))
(cdr rest)))
temps)
,@(mapcar #'fourth meths))))

最佳答案

那实际上是一些旧代码。 get-setf-method实际上被get-setf-expansion取代了如 Issue SETF-METHOD-VS-SETF-METHOD Writeup 中所述.所以这些天你应该感兴趣的是 get-setf-expansion .它返回的值是您需要将值安全地存储在某个位置的代码片段。这一点非常重要,因为很容易错误地编写 modyfing 宏。

至于为什么有些值可以是nilget-setf-expansion 文档中的示例之一实际上显示了一些值可以是nil :

(get-setf-expansion 'x)
;=> NIL, NIL, (#:G0001), (SETQ X #:G0001), X

但是这些值是什么?为此,我们需要查看文档的语法:

Syntax:

get-setf-expansion place &optional environment

vars, vals, store-vars, writer-form, reader-form

Arguments and Values:

place—a place.

environment—an environment object.

vars, vals, store-vars, writer-form, reader-form—a setf expansion.

这五个返回值在 5.1.1.2 Setf Expansions 中有描述。 :

List of temporary variables a list of symbols naming temporary variables to be bound sequentially, as if by let*, to values resulting from value forms.

List of value forms a list of forms (typically, subforms of the place) which when evaluated yield the values to which the corresponding temporary variables should be bound.

List of store variables a list of symbols naming temporary store variables which are to hold the new values that will be assigned to the place.

Storing form a form which can reference both the temporary and the store variables, and which changes the value of the place and guarantees to return as its values the values of the store variables, which are the correct values for setf to return.

Accessing form a form which can reference the temporary variables, and which returns the value of the place.

那么示例中的这些值是什么意思?

(get-setf-expansion 'x)
;⇒ NIL, NIL, (#:G0001), (SETQ X #:G0001), X

写入变量x ,我们不需要任何临时存储,并且由于没有临时值,我们不需要任何形式来为它们产生值。我们在这里可以注意到,第一个和第二个值始终是列表,并且它们的长度应始终相同。第三个值是存储变量列表。这是一个列表,因为我们实际上可以使用 setf修改多个值,但在本例中只有一个。这里的变量是宏应该实际存储新值的地方。然后,它是writer-form (setq x #:g0001)这实际上会负责将值(value)放在适当的位置。 x ,当然是读取值的一种简单方法。

作为一个更复杂的示例,请查看 SBCL 的这段文字记录:

CL-USER> (defstruct person
person-name)
;⇒ PERSON

CL-USER> (get-setf-expansion '(char (person-name (first (second list-of-list-of-persons))) 3))
; (#:TMP965)
; ((PERSON-NAME (FIRST (SECOND LIST-OF-LIST-OF-PERSONS))))
; (#:NEW964)
; (SB-KERNEL:%CHARSET #:TMP965 3 #:NEW964)
; (CHAR #:TMP965 3)

这意味着,如果我们想更改人员列表中第二个人员列表中第一个人姓名的第四个字符,我们可以这样做:

(let* ((temp965 (person-name (first (second list-of-list-of-persons))))
(old-char (char tmp965 3))) ; optional
(setq new964 <compute-new-value>)
(sb-kernel:%charset tmp965 3 new964))

我们可以根据需要计算新值(只需填写 <compute-new-value> ),如果需要,我们甚至可以引用旧值(通过包含可选行)。我们需要做的就是设置 new964到新值,然后执行给我们的 writer-form

get-setf-expansion还有更多例子关于堆栈溢出:

关于lisp - 关于onlisp中的广义变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21407125/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com