Common Lisp中有一些读取宏' #' #P,但是如何编写读取宏呢?
像这样:
#T"hello world"
====================>
(gettext "hello world")
Run Code Online (Sandbox Code Playgroud) 最近我试着阅读关于cl-mysql的代码,但是却陷入了困境#+.
试图google它,但没有工作,所以转到这里
(defun make-lock (name)
#+sb-thread (sb-thread:make-mutex :name name)
#+ecl (mp:make-lock :name name)
#+armedbear (ext:make-thread-lock)
#+ (and clisp mt) (mt:make-mutex :name name)
#+allegro (mp:make-process-lock :name name))
Run Code Online (Sandbox Code Playgroud)
看起来它适用于不同的后端lisp编译器.但仍然不知道为什么写这样的东西.他说,任何人都可以帮助我说清楚.
我在Common Lisp中编写自己的x86-64汇编程序,它为x86-64的子集生成正确的二进制代码.我使用自定义阅读器宏将汇编代码转换为语法树,并按预期工作.
我试图完成的是允许在汇编代码中使用Lisp代码,这样我可以使用Lisp作为汇编程序的宏语言.我#a用作宏调度字符并#e为读者发出信号.内部读者#l更改为Lisp模式并#a返回到汇编模式#e(对于读取器宏的信号结束)应该在两种模式下都有效.
我不明白的是如何将评估代码的结果输出回输入流(在其余代码之前处理),或者如何再次读取Lisp代码输出,以便输出可以适当地处理Lisp代码(它将是汇编代码)(与汇编代码的其余部分相同).我怎样才能实现这一目标?
旁注:这是我的第一个读者宏,因此可能存在设计缺陷.我认为我将Lisp代码读入字符串的方法不一定是最好的方法,如果有一些更短和更惯用的方法来做到这一点.
这是我的阅读器宏的简化版本:
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun get-last-character-string (my-string)
"This function returns a string consisting of the last character of the input string."
(subseq my-string (1- (length my-string))))
(defun get-string-without-last-character (my-string)
"This function returns a string without the last character of the input string."
(subseq my-string 0 (1- (length my-string))))
(defun get-string-without-invalid-last-character (my-string invalid-last-characters)
"If the last character of … 最近,我遇到了所谓的哈希点Common Lisp阅读器宏,我想知道它是如何工作的以及它的作用.使用搜索引擎没有多大帮助,所以任何示例,解释和特别是用例都是最受欢迎的.
这个问题在一定程度上重新接种到这个和这个对elisp的.基本上,如何读取和评估反向报价?正在发生什么过程?标准是否对此有所说明?
这是我所期望的,但它不会发生:符号`是一个读者宏 - 并被翻译成某种(BACKQUOTE ...)宏/特殊形式(类似于'被翻译(QUOTE ...)).这不会发生,事实上,Common Lisp甚至没有BACKQUOTE宏.
发生了什么(SBCL):
CL-USER> (defparameter *q* (read-from-string "`(a b ,c)"))
*Q*
CL-USER> *q*
`(A B ,C)
CL-USER> (car *q*)
SB-INT:QUASIQUOTE
CL-USER> (cdr *q*)
((A B ,C))
Run Code Online (Sandbox Code Playgroud)
与预期有所不同,但还可以.现在,,C它本身就是一个有趣的野兽:
CL-USER> (type-of (third (cadr *q*)))
SB-IMPL::COMMA
Run Code Online (Sandbox Code Playgroud)
如果没有逗号符号,则评估读取表达式是正常的:
CL-USER> (eval (read-from-string "`(a b c)"))
(A B C)
Run Code Online (Sandbox Code Playgroud)
但是如果我想用本地绑定来评估原始表达式C,则存在一个问题:
(let ((c 10)) (eval (read-from-string "`(a b ,c)")))
; in: LET ((C 10)) …Run Code Online (Sandbox Code Playgroud) 我想以这样的方式定义读取器宏,它们只影响某个包/文件.
到目前为止,我能够加载这些文件
(let ((*readtable* (copy-readtable)))
(load "file.lisp"))
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法呢?
由Doug Hoyte阅读的书"Let Over Lambda",我发现了以下对#.符号的描述,即read-macro:
使用COMMON LISP内置的基本读取宏是#.读取时间eval宏.此读取宏允许您将对象嵌入到您读取的无法序列化的表单中,但可以使用一些lisp代码创建.
它来自第4章,本书的大部分内容可以在这里找到:http: //letoverlambda.com/index.cl/toc
这是本书中的示例,显示了每次都可以以不同的方式读取相同的表达式:
* '(football-game
(game-started-at
#.(get-internal-real-time))
(coin-flip
#.(if (zerop (random 2)) 'heads 'tails)))
(FOOTBALL-GAME
(GAME-STARTED-AT 187)
(COIN-FLIP HEADS))
* '(football-game
(game-started-at
#.(get-internal-real-time))
(coin-flip
#.(if (zerop (random 2)) 'heads 'tails)))
(FOOTBALL-GAME
(GAME-STARTED-AT 309)
(COIN-FLIP TAILS))
Run Code Online (Sandbox Code Playgroud)
接下来,作者演示了一些硬核技巧,用#宏创建变体.
因此,事实证明它#'也是某种读取宏,它通常在表示函数名称的符号之前使用.但这是否必要,他的工作到底是什么?
我可以在有#'或没有它的情况下为高阶函数添加符号:
CL-USER> (defun test nil t)
TEST
CL-USER> (funcall #'test)
T
CL-USER> (funcall 'test)
T
Run Code Online (Sandbox Code Playgroud)
取得同样的成功.
我写了一些可以取代read普通lisp 功能的函数
(defun my-read (stream &rest args)
(declare (ignore args))
(funcall (my-get-macro-character (read-char stream))))
Run Code Online (Sandbox Code Playgroud)
有没有办法将此功能用作默认阅读器?
我目前正在阅读Paul Graham的"On Lisp"一书中关于读时宏的章节.
我遇到的问题如下.当我运行他的一个例子时:
(set-dispatch-macro-character #\# #\?
#’(lambda (stream char1 char2)
‘#’(lambda (&rest ,(gensym))
,(read stream t nil t))))
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
No dispatch function defined for #\’
Run Code Online (Sandbox Code Playgroud)
为什么会这样?可能是因为我在REPL上运行它吗?有什么可以解决它?
我在 JavaScript 中有自己的 Lisp 解释器,我已经工作了一段时间,现在我想实现像 Common Lisp 中的阅读器宏。
我已经创建了 Streams(除了像 那样的特殊符号几乎可以工作,@ , ` ')但是当它加载包含脚本(具有 400 行代码的 lisp 文件)的页面时,它会冻结浏览器几秒钟。这是因为我的 Streams 是基于 substring 函数的。如果我首先拆分令牌,然后使用迭代令牌的 TokenStream,它工作正常。
所以我的问题是,字符串流真的是 Common Lisp 中的东西吗?您能否添加在 CL 中创建全新语法(如 Python)的读取器宏,这简化了问题,我可以实现"""宏(不确定您是否可以将 3 个字符作为读取器宏)或其他将在 lisp 中实现模板文字的字符,例如:
(let ((foo 10) (bar 20))
{lorem ipsum ${baz} and ${foo}})
Run Code Online (Sandbox Code Playgroud)
或者
(let ((foo 10) (bar 20))
""lorem ipsum ${baz} and ${foo}"")
Run Code Online (Sandbox Code Playgroud)
或者
(let ((foo 10) (bar 20))
:"lorem ipsum ${baz} and ${foo}")
Run Code Online (Sandbox Code Playgroud)
会产生字符串
"lorem ipsum 10 and 20"
Run Code Online (Sandbox Code Playgroud)
在 Common Lisp 中,这样的事情是可能的,实现 …
我有一个 Common Lisp 阅读器宏来解析“或”关系的惰性/延迟声明,使用由管道符(“|”)分隔的中缀语法以及标准列表括号和关键字文字。考虑形式 (:a :b|:c) - 它表示一个 2 部分元组,其中第一个元素肯定是 :a,第二个元素是 :b 或 :c。例如,可以推断整个元组的有效形式是 (:a :b) 或 (:a :c)。
我已经有函数封装的逻辑来解构 read 宏之后的这些元组列表形式。但在阅读时,我需要解析像 :a|:b|:c 这样的形式,并用移除的管道标记它,比如 (:lazy-or :a :b :c)。中缀语法的使用纯粹是为了面向读者的形式;中缀形式是短暂的,会在阅读阶段立即被丢弃,取而代之的是用 :lazy-or 标记的等效合法 lisp 形式。
所以我制作了一个几乎可以正常工作的 read 宏,但目前需要在第一个 or-form 关键字元素之前使用一个额外的管道作为一种读者标志(我希望这不是必需的完全),并且它目前无法使用嵌套括号或拼接符号推断类似形式作为等效(如在算术中,2+(3*4)具有相同的运算顺序,等效形式,如2+3*4)。
宏(源自此处的“斜线阅读器”:http : //www.lispworks.com/documentation/HyperSpec/Body/f_rd_rd.htm):
(defun pipe-reader (stream char)
(declare (ignore char))
`(:lazy-or . ,(loop for dir = (read stream t nil t)
then (progn (read-char stream t nil t)
(read stream t nil t))
collect dir
while (eql …Run Code Online (Sandbox Code Playgroud) macros common-lisp infix-notation infix-operator reader-macro
从这些函数的签名来看,明显的区别在于set-macro-character允许您为单个字符设置reader宏功能,并set-dispatch-macro-character允许您为两个字符的任意组合设置它.这是唯一的区别吗?我什么时候需要使用一个而不是另一个?