Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Macros 是否可以使用符号宏来获得类似行为的标签?_Macros_Common Lisp - Fatal编程技术网

Macros 是否可以使用符号宏来获得类似行为的标签?

Macros 是否可以使用符号宏来获得类似行为的标签?,macros,common-lisp,Macros,Common Lisp,换句话说,是否可以以类似于flet或labels的方式局部定义函数?我的最终目标是创建一个类似于labels的宏,它不使用常规函数,而是使用funcallable标准类的实例,而不必使用funcall。用例可能如下所示: (funcallable-let ((foo func-class :initargs ...)) (foo ...)) symbol macrolet似乎仅在不处于头部位置时才展开。如果我尝试(setf(symbol function'foo)(make instanc

换句话说,是否可以以类似于
flet
labels
的方式局部定义函数?我的最终目标是创建一个类似于
labels
的宏,它不使用常规函数,而是使用
funcallable标准类的实例,而不必使用
funcall
。用例可能如下所示:

(funcallable-let ((foo func-class :initargs ...))
  (foo ...))
symbol macrolet
似乎仅在不处于头部位置时才展开。如果我尝试
(setf(symbol function'foo)(make instance'some functualable class))
这将全局设置此符号,而不是包含
let
的范围


以下是我目前可以得到的结果(但它不起作用,因为macrolet在这种情况下不会扩展…)


这是经过修改的Lars'Brinkoff宏:

(defmacro funcallable-let (bindings &body body)
  (loop
     :for binding :in bindings
     :for symbol := (gensym)
     :for name := (car binding)
     :for class := (cadr binding)
     :for init-args := (cddr binding)
     :collect `(,symbol (make-instance ',class ,.init-args)) :into lets
     :collect `(,name (&rest args) (apply ',symbol args)) :into flets
     :collect symbol :into ignorables
     :finally
     (return
       `(let ,lets
          (declare (ignorable ,@ignorables))
          (flet ,flets ,@body)))))

这也行不通。

我不知道你想做什么,但也许是这个

(defmacro funcallable let(绑定和正文)
(让((gensym(循环重复(长度绑定)收集(gensym)))
`(让绑定中的(name-value)循环,gensyms中的g循环
收集“(,g,value))
绑定中的(名称值)循环和gensyms中的g循环
收集“(,name(&rest参数)(apply,g参数)))
(@body)))
示例用法:

(funcallable-let ((foo (make-instance 'some-funcallable-class :initargs ...)))
  (foo ...))

有关类似问题,请参见CLtL2的
GENERIC-FLET
GENERIC-LABELS
,以及在ANSI Common Lisp中删除它的原因


因此,我们希望
f
的值是可函数化的对象,这样像
(setf(state of f)new state)
这样的东西就可以工作了,而且还需要
f
的宏定义,这样
(f1 2 3)
就可以扩展到
(funcall f1 2 3)
。让我们先编写一些直接代码。首先,使用您的
func
定义,但使用稍微不同的funcallable实例函数,以便我们可以传入一些参数并查看它们是什么:

(defclass func ()
  ((state :initarg :state :accessor state-of))
  (:metaclass sb-mop:funcallable-standard-class))

(defmethod initialize-instance :after ((this func) &rest initargs)
  (declare (ignore initargs))
  (sb-mop:set-funcallable-instance-function
   this (lambda (&rest args)
          (format t "~&I am: ~s, my state is: ~s, my args were ~s" this (state-of this) args))))
然后,我们可以编写希望
functualable let
展开的代码。如输出所示,头部位置的
f
最终是对funcallable实例的调用,但非头部位置的
f
是一个变量,它将funcallable实例作为值,因此您可以,例如
(setf(state of f)new state)

宏观扩张看起来是正确的:

CL-USER> (pprint (macroexpand '(funcallable-let ((f :state 34))
                                (f 1 2 3))))

(LET ((F (MAKE-INSTANCE 'FUNC :STATE 34)))
  (MACROLET ((F (&REST ARGS)
               `(FUNCALL F ,@ARGS)))
    (F 1 2 3)))
而且行为似乎是正确的(您可以使用
(f…
(funcall f…
)调用,并且您可以
(setf(f的状态)…)

CL-USER>(可函数let((f:state 34))
(f 1 2 3)
(setf(联邦州)89)
(f 4 5 6)
(setf(联邦州)62)
(全部f 7 8 9))
我是:#,我的状态是:34,我的参数是(1 2 3)
我是:#,我的状态是:89,我的参数是(4 5 6)
我是:#,我的状态是:62,我的参数是(7 8 9)
无

symbol macrolet
仅当符号用作变量名时才会展开。头部位置是函数名,而不是变量名,因此不会在那里展开。如果希望它在函数位置展开,请使用
macrolet
@Barmar和
macrolet
有一个完全相反的问题-我无法o将符号与
funcall
reduce
一起使用,或者你做了什么…(或者至少我看不出我是怎么做的)。我不确定你想实现什么,
flet
标签
都没有提供。也许如果你展示了一个用例。如果
macrolet
适用于一种情况,而
symbol macrolet
适用于另一种情况,为什么不编写一个扩展为两种情况的宏,这样你就可以得到适用于两种情况的东西呢?@JoshuaTaylor我希望有一种更便宜的方法:)不,这不行,因为它会在funcallable对象周围创建一堆包装函数,这违背了使用funcallable对象的目的(您将无法专门化这些对象上的方法/执行其他有用的操作,如更改插槽值等)@wvxvw我现在更仔细地阅读了其他答案,与此类似,只是我使用了
macrolet
而不是
flet
。谢谢,这很有趣,我不知道这些宏曾经存在过。然而,在我试图做的事情中,类定义在宏之外,因此我可以在多个函数之间以统一的方式重用处理扩展类型函数的代码。从技术上讲,即使是现在,也没有什么能阻止我这么做,唯一困扰我的是过于冗长的语法(即,我必须编写
(funcall'foo…
,而不仅仅是
(foo…
)。好吧,这很有效,除了在主体内部
(funcall'f…
)没有按预期展开,但是
(funcall'f…
)(来自
let
)的剩余代码。我的变体生成非常相似的代码,除了您有
\`(funcall',name,@args)
我有
(列表“应用”,名称“args”)
我认为这些应该是相同的…@wvxvw宏扩展代码并不重要,只要它生成的代码是相同的。您将无法使
(funcall'f…
工作。
funcall
采用一个符号,如果它是一个符号,则表示“在全局环境中由该符号命名的函数”。(I)您使用的是funcallable,而不是function。(ii)您没有在全局环境中工作。甚至
(flet((f…)(funcall'f…)
调用全局,而不是局部。啊……好吧,现在我明白了,我想我可以
funcall
一个符号,它是
标签中定义的名称,但实际上我必须传递一个函数引用,而不是符号。好的,谢谢解释。
(let ((f (make-instance 'func :state 34)))
  (macrolet ((f (&rest args)
               `(funcall f ,@args)))
    (f 1 2 3)
    (setf (state-of f) 89)
    (f 4 5 6)))

; I am: #<FUNC {1002A0B329}>, my state is: 34, my args were (1 2 3)
; I am: #<FUNC {1002A0B329}>, my state is: 89, my args were (4 5 6)
(defmacro funcallable-let (bindings &body body)
  `(let (,@(loop :for (name . initargs) :in bindings
             :collect `(,name (make-instance 'func ,@initargs))))
     (macrolet (,@(loop :for (name . initargs) :in bindings
                    :collect `(,name (&rest args)
                                     `(funcall ,',name ,@args))))
       ,@body)))
CL-USER> (pprint (macroexpand '(funcallable-let ((f :state 34))
                                (f 1 2 3))))

(LET ((F (MAKE-INSTANCE 'FUNC :STATE 34)))
  (MACROLET ((F (&REST ARGS)
               `(FUNCALL F ,@ARGS)))
    (F 1 2 3)))
CL-USER> (funcallable-let ((f :state 34))
           (f 1 2 3)
           (setf (state-of f) 89)
           (f 4 5 6)
           (setf (state-of f) 62)
           (funcall f 7 8 9))
I am: #<FUNC {1002BEC389}>, my state is: 34, my args were (1 2 3)
I am: #<FUNC {1002BEC389}>, my state is: 89, my args were (4 5 6)
I am: #<FUNC {1002BEC389}>, my state is: 62, my args were (7 8 9)
NIL