Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/reporting-services/3.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 有没有办法混合使用LISP';s宏观及;可选和&;关键参数?_Macros_Lisp_Common Lisp - Fatal编程技术网

Macros 有没有办法混合使用LISP';s宏观及;可选和&;关键参数?

Macros 有没有办法混合使用LISP';s宏观及;可选和&;关键参数?,macros,lisp,common-lisp,Macros,Lisp,Common Lisp,我想定义一个LISP宏,比如dolist,它允许我定义一个可选的输出参数。在下面的案例研究中,此宏将被称为doread。它将从文件中读取行,并返回通过这种方式找到的行数 (let((第0行)) (数据读取(行文件行) 用线做点什么 (incf行) 问题是要让行在上面的宏中工作 我可以用&key做我想做的事情,但不能用&optional&key(而且&key是必需的,因为我想控制文件的读取方式;例如,用读取或读取行或任何东西) 现在,下面的方法起作用了,但它的作用方式是错误的。此处,out参数必

我想定义一个LISP宏,比如
dolist
,它允许我定义一个可选的输出参数。在下面的案例研究中,此宏将被称为
doread
。它将从文件中读取行,并返回通过这种方式找到的行数

(let((第0行))
(数据读取(行文件行)
用线做点什么
(incf行)
问题是要让
行在上面的宏中工作

我可以用&key做我想做的事情,但不能用&optional&key(而且&key是必需的,因为我想控制文件的读取方式;例如,用
读取
读取行
或任何东西)

现在,下面的方法起作用了,但它的作用方式是错误的。此处,
out
参数必须是
键,而不是可选的(&C):

;;这种方法有效。。。
(解除宏读取((it f&key out(读取))和正文)
“用于在文件或字符串上运行的迭代器。”
(let((str(gensym)))
`(打开文件(,str f)
(循环for,it=(funcall,take,str nil)
尽管如此,它确实如此
(progn,@body))
(中,外)
;; 让我定义读取文件第一行的内容
(第1(f)段)
“阅读所有内容,直到第一个空行。”
(输出到字符串)
(doread(xf:take#’read-line)
(如果(相等“”(字符串修剪“(#\Space#\Tab)x))
(返回)
(格式s“~a~%”x(()()))
(打印(para1));=>显示直到第一个空行的所有内容
我想做的是以下几点(注意,
out
现在已移动到
&可选

(defmacro-doread((it-f&optional out&key(take#'read))和body)
“用于在文件或字符串上运行的迭代器。”
(let((str(gensym)))
`(打开文件(,str f)
(循环for,it=(funcall,take,str nil)
尽管如此,它确实如此
(progn,@body))
(中,外)
如果这有效的话,我可以做类似的事情

(defun para1(f)
“将所有内容打印到第一个空白行。
返回以这种方式找到的行“
(let((第0行))
(doread(xf行:采用#读行)
(如果(相等“”(字符串修剪“(#\Space#\Tab)x))
(返回)
(和(incf行)(格式t“~a~%”x()()))
但是我使用的是
&可选的out
我得到的

 loading /Users/timm/gits/timm/lisp/src/lib/macros.lisp
*** - GETF: the property list (#'READ-LINE) has an odd length

您不能混合使用
&可选的
&键
,只能传递关键字参数。但是,您可以定义语法 允许与关联的参数的可选列表 来源

例如:

(defpackage :so (:use :cl :alexandria))
(in-package :so)

(defmacro do-read ((entry source &optional result) &body body)
  (destructuring-bind (source &key (take '#'read)) (ensure-list source)
    (once-only (take)
      `(loop
          :with ,entry
          :do (setf ,entry (handler-case (funcall ,take ,source)
                             (end-of-file () (loop-finish))))
            (progn ,@body)
          :finally (return ,result)))))
DO-READ
的语法可以写成:

(DO-READ (ENTRY [SOURCE|(SOURCE &KEY TAKE)] &OPTIONAL RESULT) . BODY)
这并不是一种不寻常的语法w.r.t.标准Lisp表单(请参见
LET
、lambda列表中的关键字synax、
defstruct
等)。 您可以添加更多关键字参数以及
TAKE

评论
  • 在宏中,我更喜欢将循环关键字作为关键字而不是符号发出 在宏的定义包中;否则,在宏展开时 在代码中,您可能会得到以宏的 包(即
    SO::WITH
    而不是
    :WITH
    ),它会快速 不可读

  • 读取行
    返回NIL可以,但从
    读取
    返回NIL则不行,因为NIL可能是一个成功读取的值。在 一般情况下,由于
    TAKE
    由用户提供,因此 我不知道零是不是一个可以接受的结果。这就是为什么我抓住了
    改为文件结尾
    。如果您想从其他来源读取,您还可以检查辅助返回值,或记录它们也发出了条件信号

  • 条目
    变量的范围被扩展,以便可以
    ENTRY
    本身;在您的情况下,
    OUT
    不能等于
    IT
    , 因为一旦你退出循环,你就再也无法访问它了 这是一个小问题,但这可能是有用的

  • 我没有将
    包含在-OPEN-FILE
    中,以防您想从 文件(流)以外的内容

  • 引用了
#“READ”
,这在这里并不重要,但在宏中有一个好习惯,这样您实际上是在求值时求值,而不是在宏扩展时

例子 打印所有字符并返回
\f

(with-input-from-string (in (format nil "~{~a~%~}" *features*))
  (let ((lines 0))
    (do-read (line in lines)
      (incf lines))))
打印字符串中的行数。

适用于我:

(defmacro doread ((it f &optional out &key (take #'read)) &body body)
  "Iterator for running over files or strings."
  (let ((str (gensym)))
    `(with-open-file (,str ,f)
       (loop for ,it = (funcall ,take ,str nil)
             while ,it do
             (progn ,@body))
       ,out)))

(defun para1 (f)
  "Print  everything up to first blank line. 
   Return the lines found in that way"
  (let ((lines 0))
    (doread (x f lines :take #'read-line)
      (if (equalp "" (string-trim '(#\Space #\Tab) x))
          (return)
        (and (incf lines) (format t "~a~%" x))))))
在LispWorks中使用它:

CL-USER 104 > (para1 (capi:prompt-for-file "text file"))
;;; -*- mode: Lisp; Base: 10 ; Syntax: ANSI-Common-Lisp ; buffer-read-only: t; -*-
;;; This is ASDF 3.3.3: Another System Definition Facility.
;;;
;;; Feedback, bug reports, and patches are all welcome:
;;; please mail to <asdf-devel@common-lisp.net>.
;;; Note first that the canonical source for ASDF is presently
;;; <URL:http://common-lisp.net/project/asdf/>.
;;;
;;; If you obtained this copy from anywhere else, and you experience
;;; trouble using it, or find bugs, you may want to check at the
;;; location above for a more recent version (and for documentation
;;; and test files, if your copy came without them) before reporting
;;; bugs.  There are usually two "supported" revisions - the git master
;;; branch is the latest development version, whereas the git release
;;; branch may be slightly older but is considered `stable'
15
CL-USER 104>(para1(capi:提示输入文件“文本文件”))
模式:Lisp;基:10;语法:ANSI公共Lisp;缓冲区只读:t-*-
这是ASDF 3.3.3:另一个系统定义工具。
;;;
;欢迎提供反馈、错误报告和修补程序:
请发邮件到。
首先请注意,ASDF的规范源目前是
;;; .
;;;
如果你从其他任何地方获得这本书,并且
使用它时遇到问题,或者发现bug,您可能需要在
;以上位置为最新版本(和文档)
;和测试文件,如果您的副本中没有这些文件),则在报告之前
通常有两个“受支持”的版本-git主版本
branch是最新的开发版本,而git版本
分支可能稍老,但被认为是“稳定的”
15

只是一旦你想指定
:就需要提供可选的arg。这是一个常见的陷阱,这就是为什么可选的和关键字arg的组合不受欢迎的原因。

这很好,谢谢。
解构bind
?很酷。没有想到要使用它。但是
一次只
让我感到困惑。和其他人。你能澄清一下吗?
只执行一次
就像使用gensyms的
一样
对于宏卫生也是如此。但是要确保被gensym替换的变量在宏体中只执行一次。所以是一个非常实用的宏,而且大多数情况下都是这样
CL-USER 104 > (para1 (capi:prompt-for-file "text file"))
;;; -*- mode: Lisp; Base: 10 ; Syntax: ANSI-Common-Lisp ; buffer-read-only: t; -*-
;;; This is ASDF 3.3.3: Another System Definition Facility.
;;;
;;; Feedback, bug reports, and patches are all welcome:
;;; please mail to <asdf-devel@common-lisp.net>.
;;; Note first that the canonical source for ASDF is presently
;;; <URL:http://common-lisp.net/project/asdf/>.
;;;
;;; If you obtained this copy from anywhere else, and you experience
;;; trouble using it, or find bugs, you may want to check at the
;;; location above for a more recent version (and for documentation
;;; and test files, if your copy came without them) before reporting
;;; bugs.  There are usually two "supported" revisions - the git master
;;; branch is the latest development version, whereas the git release
;;; branch may be slightly older but is considered `stable'
15