这是Paul Graham撰写的On Lisp上的简化示例(方案类似于语法)。
(define-macro (bar)
(let ((x 10) (y '(1 2 3)) (z 'foo))
`(list ,x `(,',z ,,@y))))
Run Code Online (Sandbox Code Playgroud)
我知道,,@y应该如何工作,但不能确切确定,',z应该如何工作,首先应该评估什么,以什么顺序进行评估。(我知道它应该评估为foo符号,因为它(10 (foo 1 2 3))以guile形式返回,但是我不确定确切的步骤是什么)。
我需要在JavaScript中使用lisp来获得结果:
(10 ((unquote z) 1 2 3))
Run Code Online (Sandbox Code Playgroud)
因为它只评估它从左到右的形式(我只处理特殊的,,逗号)。您应该如何评估此表达式。
书中也有这个例子:
(defmacro propmacro (propname)
`(defmacro ,propname (obj)
`(get ,obj ',',propname)))
Run Code Online (Sandbox Code Playgroud)
',',应该如何评估?在这种情况下应采取什么步骤?
还有其他带有反引号/准引号的怪异情况吗?您能否显示这些示例以及应如何评估它们以及以什么顺序进行示例?
目前正在学习常见的口齿不清,继Peter Seibel的Practical Common Lisp(我在第11章,关于收藏)之后,我很难理解setf幕后的工作方式.
考虑这个表达式:
(setf a 10)
Run Code Online (Sandbox Code Playgroud)
我完全理解解释器如何(1)检索名为的变量a,以及(2)更改它指向的值10.
现在,我是特定集合的例子,例如列表,向量或散列表,setf也可用于更改集合包含的值.例如,使用向量:
(defparameter *x* '(a b c d))
(setf (elt *x* 1) bb)
Run Code Online (Sandbox Code Playgroud)
这让我怀疑setf,因为它最终会找到非平凡的信息,或制造黑魔法.我看到了多种可能性.
该(elt *x* 1)表达式返回'b,因此setf实际上被有工作(setf b bb).然后我不明白如何setf推断*x*它必须修改哪个对象(这里是列表),而不具有elt保持它来自集合的指示的返回值,以及指向所述集合的指针.看似复杂.
这个想法就像setf宏一样,它直接与它一起工作(setf (elt *x* 1) bb),因此可以提取elt *x* 1部件来推断使用哪个对象/集合,因此必须进行修改.
它似乎不是非常有效,也不可靠,也不能抵抗复杂的操作.但是,因为我无法运行此代码:
(funcall (find-symbol (concatenate 'string "E" "LT")) *x* 1) ; -> B …Run Code Online (Sandbox Code Playgroud) 在Common Lisp中,如何定义一个"元宏",它将宏(和其他参数)列表作为参数,并组合这些宏以生成所需的代码.
这个问题等同于编写一个"高阶宏",它定义了其他宏的变量列表中的宏.
提示问题的具体情况是我对CLSQL的实验,我想从CLSQL-testsuite重新表达员工类
(clsql:def-view-class employee ()
((employee-id
:db-kind :key
:db-constraints (:not-null)
:type integer)
(first-name
:accessor employee-first-name
:type (string 30)
:initarg :first-name)
(last-name
:accessor employee-last-name
:type (string 30)
:initarg :last-name)
(email
:accessor employee-email
:type (string 100)
:initarg :email)
(company-id
:type integer
:initarg :company-id)
(company
:accessor employee-company
:db-kind :join
:db-info (:join-class company
:home-key companyid
:foreign-key companyid
:set nil))
(manager-id
:type integer
:nulls-ok t
:initarg :manager-id)
(manager
:accessor employee-manager
:db-kind :join
:db-info (:join-class employee
:home-key managerid
:foreign-key emplid
:set nil))))
Run Code Online (Sandbox Code Playgroud)
如
(def-view-class-with-traits …Run Code Online (Sandbox Code Playgroud) 我得到了这个答案/sf/answers/4922329401/关于编写一个简单的宏来记录宏扩展时的时间,然后总是返回该时间。
#lang racket
(begin-for-syntax
(define the-time (current-seconds)))
(define-syntax (macro-expansion-seconds stx)
(datum->syntax stx the-time))
(macro-expansion-seconds)
(macro-expansion-seconds)
(macro-expansion-seconds)
Run Code Online (Sandbox Code Playgroud)
它工作得很好,但现在有没有一种简单的方法可以在(macro-expansion-seconds)不评估它的情况下查看它的扩展版本?(用于调试更复杂的)
我正在尝试在 Common Lisp 中编写一个宏,它接受任意数量的表达式并构建一个包含每个表达式的列表,然后在一行中对其进行评估。例如,如果我将宏命名为
(defmacro list-builder (&rest exp)
...)
Run Code Online (Sandbox Code Playgroud)
我跑
(let ((X 1) (Y 2)) (list-builder (+ X Y) (- Y X) X))
Run Code Online (Sandbox Code Playgroud)
我希望它返回:
'((+ X Y) 3 (- Y X) 1 X 1)
Run Code Online (Sandbox Code Playgroud)
到目前为止我能做的最好的是使用代码获取表达式列表
(defmacro list-builder (&rest exp)
`',@`(',exp ,exp))
INPUT: (let ((X 1) (Y 2)) (list-builder (+ X Y) (+ Y X) X))
'((+ X Y) (+ Y X) X)
Run Code Online (Sandbox Code Playgroud) 我以前不止一次有过这个问题。
是否可以使用具有相同名称的包装器在本地ff透明地隐藏函数?
即,如何在本地将 (f 包裹的参数...) 扩展为 (f args...)?
Flet 似乎允许我们这样做,但有局限性,即生成的包装器不可设置。是否有可能在不诉诸舰队的情况下这样做?
理想情况下,会有一个宏让我们编写“包装”f调用,并将代码扩展为原始的“非包装”f调用。
起初我相信macrolet可能是这样,因为它在文档中说它首先扩展宏然后在扩展形式上应用setf,但我无法使用它(继续阅读下面)。
这在某些参数是隐式的并且不应一遍又一遍地重复以获取更多 DRY 代码的上下文中很有用。
在我之前的问题 (let-curry) 中有一个特定的例子。试图“自动”分配函数的一些参数(let-curry)。
我在那里得到了一些很好的答案,但是,我遇到了一些限制。通过使用 flet 来完成函数名称的这种局部“阴影”到其上的包装器,此类包装器不可设置,因此,此类包装器不能像原始函数一样灵活使用,只能读取值,而不是写入.
通过上面的链接,如何编写宏 flet-curry 并使包装函数可设置?
奖励:该宏能否以 0 运行时开销将包装的调用扩展到原始调用?
我尝试在该帖子中选择答案并使用 macrolet 而不是 flet 无济于事。
谢谢!
我被要求为这个通用问题举一个具体的例子。
代码中的愿望注释:
(locally (declare (optimize safety))
(defclass scanner ()
((source
:initarg :source
:accessor source
:type string)
(tokens
:initform nil
:accessor tokens
:type list)
(start
:initform 0
:accessor start
:type …Run Code Online (Sandbox Code Playgroud) 我目前正在学习格雷厄姆的书"ANSI Common Lisp"中的lisp,作为练习,我正在编写基于Julian-day的日历计算.如您所知,复活节星期日每年都在变化,大约有10个特殊日子,实际日期取决于复活节星期日.
我想为每一天定义一个函数,所有函数都遵循以下模式:
(defun carnaval (year)
"Carnaval Monday of YEAR.
This is 48 days before Easter Sunday."
(- (easter year) 48))
Run Code Online (Sandbox Code Playgroud)
使用宏似乎是合适的,而不是重复10次类似的声明:
(defmacro %defeasterday (function-name screen-name offset)
`(defun ,function-name (year)
,(format nil "~A of YEAR.~%~%This is ~A day~:p ~A Easter Sunday"
screen-name
(abs offset)
(if (< 0 offset) "after" "before"))
(+ (easter year) ,offset)))
Run Code Online (Sandbox Code Playgroud)
(起始%标记我的意图是不将宏导出到定义它的包中.)
该宏可用于为日期基于东方星期日的每一天定义一个函数:
(%defeasterday carnaval "Carnaval Monday" -48)
(%defeasterday mardi-gras "Mardi gras" -47)
(%defeasterday ash "Ash Wednesday" -46)
…
Run Code Online (Sandbox Code Playgroud)
现在,为了练习,我想将所有数据打包到列表中并%defeasterday在其项目上使用宏.我的尝试是
(mapc #'(lambda …Run Code Online (Sandbox Code Playgroud) 我正在尝试通过《Common Lisp:符号计算的温和介绍》一书来学习 Common Lisp 。此外,我正在使用 SBCL、Emacs 和 Slime。
在第 7 章中,作者提出以下建议lambda expressions:

这让我感到困惑,因为 SBCL 的 REPL 返回:
CL-USER> #'lambda
#<CLOSURE (:MACRO LAMBDA) {1000D736DB}>
Run Code Online (Sandbox Code Playgroud)
显然,作者使用了Lisp Works(不是 100% 确定)。我认为这与上述差异无关。不过,我觉得还是提一下比较好。
我的 SBCL 的 REPL 也返回macro了众所周知的宏,例如and:
CL-USER> #'and
#<CLOSURE (:MACRO AND) {1000D7365B}>
Run Code Online (Sandbox Code Playgroud)
请注意,具有“普通”功能的行为例如append是不同的:
CL-USER> #'append
#<FUNCTION APPEND>
Run Code Online (Sandbox Code Playgroud)
这里的这篇文章似乎稍微触及了lambda 表达式的非单一性质。但是,它没有提到任何有关标记的内容。
我是否遗漏了 lambda 表达式的本质?
我有:
(defmacro assign (name value)
(format t "assigning ~A to ~A~%" `,name `,value))
(defun opcode-call (&rest args)
(mapcar (lambda (arg)
(if (stringp arg)
(let ((var (gensym)))
(assign var arg)
var)
arg))
args))
Run Code Online (Sandbox Code Playgroud)
当我编译操作码调用时,REPL输出:
assigning VAR to ARG
OPCODE-CALL
Run Code Online (Sandbox Code Playgroud)
为什么在编译时对赋值进行求值?