Posted 2020-09-23 02:00:36 GMT
setf可能な場所なのかどうかを確認したい、というのは、そもそもどういう動機からなのかというと、身近な例では、(setf nthcdr)
等と書いた時に、
(let ((x (list 0 1 2 3 4)))
(setf (nthcdr 1 x) (list 'a 'b 'c))
x)
!Error: Undefined operator (setf nthcdr) in form ((setf nthcdr) #:|Store-Var-34450| #:g34451 #:g34452).
となってしまい、あれ、(setf nthcdr)
って設定されてないんだっけ?というようなことを防止したい、というような動機です。
上記の場合、
(let ((x (list 0 1 2 3 4)))
(setf (cdr (nthcdr 0 x)) (list 'a 'b 'c))
x)
→ (0 a b c)
と書き直せば良いのですが。
setf
できそうな場所は全部setf対応しておく等々、色々ありますが、まず、setf
して回るのは、処理系を改造することになるので、ちょっと嫌なのと、やるとしてもsetf
の展開方法が処理系ごとに結構違っているので、setf
を設定するコードの可搬性を担保するのが結構難しい。
次に、ユーティリティマクロで囲んだり、setf
の類似品を作る的なところですが、この問題をコードウォークして解決するとしても、局所関数/マクロでsetfを定義できたりするので結構大変でしょう。
標準規格で定義されているsetfの場所以外のものは一切書かない、というのは若干寂しいですが、これはこれでありかなと思います。
標準の(setf place)を全部把握したい、ということで、CLHS: 5.1.2 Kinds of Placesで定義されているものを、列記してみます。
これは問題ないでしょう
(setf bit)
(setf c[ad]+r) ;car cdr系全部
(setf char)
(setf class-name)
(setf compiler-macro-function)
(setf documentation)
(setf elt)
(setf fdefinition)
(setf fifth)
(setf fill-pointer)
(setf find-class)
(setf first ... tenth) ; firstからtenthまで
(setf rest)
(setf get)
(setf getf)
(setf gethash)
(setf ldb)
(setf logical-pathname-translations)
(setf macro-function)
(setf mask-field)
(setf nth)
(setf readtable-case)
(setf row-major-aref)
(setf sbit)
(setf schar)
(setf slot-value)
(setf subseq)
(setf svref)
(setf symbol-function)
(setf symbol-plist)
(setf symbol-value)
上記に加えて、Applyのフォームと組合せ可能なものとして、aref
、bit
、sbit
があるので、
(setf (apply #'aref))
(setf (apply #'bit))
(setf (apply #'sbit))
上記の関数フォームに組合せ可能なものとして更にvalues
(setf values)
さらに組合せ可能なものとして、the
(setf the)
setf
系マクロdecf
pop
pushnew
incf
push
remf
あたりのマクロですが、define-modify-macro
で定義したように動くので、values
と組合せて使うことは想定されていない様子。
LispWorksに至ってはエラーになります。
標準の組み合わせだけでも、結構複雑な組み合わせは可能です。
(let ((ba (make-array '(4 4)
:element-type 'bit
:initial-element 1))
(bb (make-array '(4 4)
:element-type 'bit
:initial-element 1)))
(setf (values (the bit (apply #'bit ba '(0 0)))
(the bit (apply #'bit bb '(0 0))))
(values 0 0))
(values ba bb))
→ #2A((0 1 1 1) (1 1 1 1) (1 1 1 1) (1 1 1 1))
#2A((0 1 1 1) (1 1 1 1) (1 1 1 1) (1 1 1 1))
(let ((a (make-array '(4 4) :initial-element 0)))
(incf (the integer (apply #'aref a '(1 1))))
a)
→ #2A((0 0 0 0) (0 1 0 0) (0 0 0 0) (0 0 0 0))
便利なsetf
マクロですが、あまり複雑なことはしない方が良いのかなと(月並)
ただ、(setf values)
については、色々なソースを眺めていても、あまり活用されていない気がするので、もっと活用されても良いかなと思います。
■
HTML generated by 3bmd in LispWorks 7.0.0