简化复杂的setf表达式

时间:2017-02-07 21:30:29

标签: reference macros common-lisp

为了在common-lisp中进行快速原型设计,能够在任意数据结构中轻松地功能修改对象将是方便的。这似乎涉及在数据结构中的某个位置调用一个任意函数,用函数调用的结果替换该位置的对象。 Common-lisp对特定类型的对象有许多专门的修改宏(例如incfpushgetf等),而setf用于广义位置修改(例如,setf-secondsetf-arefsetf-gethash等)。但是,不是为其他对象类型发明新的专用宏,或者必须在心理上考虑每个宏的特性(减慢开发速度),而是使用比{{1更易于使用的通用setf类修改功能可能更好。 }}。例如,代替setf(setf (second (getf plist indicator)) (1+ (second (getf plist indicator)))),可以使用common-lisp或用户提供的任何普通的一个参数函数(或lambda-expression)来编写(incf (second (getf plist indicator)))。这是对代码的尝试:

(callf (second (getf plist indicator)) #'1+)

这样的事情是否适用于所有一般情况,并且实际上是否可以简化代码?

1 个答案:

答案 0 :(得分:2)

callf

我认为您所寻找的是来自_f 12.4的OnLisp

(defmacro _f (op place &rest args)
  "Modify place using `op`, e.g., (incf a) == (_f a 1+)"
  (multiple-value-bind (vars forms var set access)
      (get-setf-expansion place)
    `(let* (,@(mapcar #'list vars forms)
            (,(car var) (,op ,access ,@args)))
       ,set)))

这使用get-setf-expansion - generalized reference处理的主力。

请注意,_f仅适用于single-value个地方。 IOW,(_f (values a b c) 1+)增加所有3个变量。 尽管如此,解决这个问题并不是那么难......

它实际上可以简化代码吗?

真的取决于您的编码风格和您正在解决的具体问题。