我目前正在通过 Graham 的书“ANSI Common Lisp”学习 lisp,作为练习,我正在编写基于儒略日的日历计算。如您所知,复活节星期日每年都在变化,还有大约 10 个其他特殊日子,其实际日期取决于复活节星期日的日期。
我想为这些日子的每一天定义一个函数,所有这些都遵循以下模式:
(defun carnaval (year)
"Carnaval Monday of YEAR.
This is 48 days before Easter Sunday."
(- (easter year) 48))
与其重复 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)))
(开始%
标志着我不打算在定义宏的包中导出宏。)
该宏可用于为日期基于东部星期日日期的每一天定义一个函数:
(%defeasterday carnaval "Carnaval Monday" -48)
(%defeasterday mardi-gras "Mardi gras" -47)
(%defeasterday ash "Ash Wednesday" -46)
…
现在,为了练习,我想将所有数据打包到一个列表中,并%defeasterday
在其项目上使用宏。我的尝试是
(mapc #'(lambda (args) (apply #'%defeasterday args))
'((carneval "Carneval Monday" -48)
(mardi-gras "Mardi gras" -47)
(ash "Ash Wednesday" -46)))
这失败了
Execution of a form compiled with errors.
Form:
#'%DEFEASTERDAY
Compile-time error:
The :macro name %DEFEASTERDAY was found as the argument to FUNCTION.
[Condition of type SB-INT:COMPILED-PROGRAM-ERROR]
这告诉我宏不仅仅是“将代码映射到代码的函数”,因为apply
它对运行它们很挑剔。
如何使用%defeasterday
上面的宏来迭代列表?
easter
(如果您出于测试目的需要临时功能,请(defun easter () 2457860)
给出 2017 年的预期答案。)