在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) 我目前正在学习格雷厄姆的书"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) 格雷厄姆的书"ANSI Common Lisp"(1996)p.137示出了使用的示例defpackage和包在-是这样
(defpackage "MY-APPLICATION"
(:use "COMMON-LISP" "MY-UTILITIES")
(:nicknames "APP")
(:export "WIN" "LOSE" "DRAW"))
(in-package my-application)
Run Code Online (Sandbox Code Playgroud)
该defpackage字符串的调用使用传达包名和列表导出符号.虽然这种风格可以在较旧的代码中看到,但今天的主要用途似乎是
(defpackage :my-application
(:use :common-lisp :my-utilities)
(:nicknames :app)
(:export :win :lose :draw))
(in-package :my-application)
Run Code Online (Sandbox Code Playgroud)
:my-application在defpackage和in-package调用中使用关键字所产生的规律性是一个小但可观的差异.
我推测,第二种形式减少了内存中程序的大小,因为关键字都是在关键字包中实现的,而文字字符串代表它们自己,而具有相同内容的文字字符串不需要共享它们的内存表示.(如果他们这样做了,可以通过改变其中一个字符串来获得奇怪的结果!)
这两种形式之间的实际差异是什么,为什么后者比前者更受欢迎?
除此之外,我偶尔也会看到
;; Pay attention to the :export line
(defpackage :my-application
(:use :common-lisp :my-utilities)
(:nicknames :app)
(:export #:win #:lose #:draw))
(in-package :my-application)
Run Code Online (Sandbox Code Playgroud)
在#引入了读者的宏,但我不知道它的影响有一个关键字,不知道如何修改defpackage声明.
使用Common Lisp进行开发时,我们有三种定义新setf形式的可能性:
我们可以定义一个函数,其名称是两个符号的列表,第一个是setf例如(defun (setf some-observable) (…)).
我们可以使用简短形式defsetf.
我们可以使用长形式defsetf.
我们可以用define-setf-expander.
我不确定每种可能性的正确或预期用例是什么.
对这个问题的回答可能会暗示最通用的解决方案和概述其他解决方案优越的背景.