全局变量a是一个 cons 单元,但不是列表。为什么 LISTP 会为其返回 T?
* (defvar a (cons 1 2))
A
* a
(1 . 2)
* (listp a)
T
全局变量a是一个 cons 单元,但不是列表。为什么 LISTP 会为其返回 T?
* (defvar a (cons 1 2))
A
* a
(1 . 2)
* (listp a)
T
我正在尝试编写一个时间线生成器,它采用包含要执行的时间和函数的 plist:
(defun run-timeline (timeline)
"Timeline is a plist with alternating timecodes and code to execute"
(alexandria:doplist (time form timeline)
(sb-ext:schedule-timer
(sb-ext:make-timer form
:thread t)
time)))
(run-timeline '(0 (print "first")
2 (print "second")))
然而,这给了我这个错误:
The value
(PRINT "first")
is not of type
(OR FUNCTION SYMBOL)
[Condition of type TYPE-ERROR]
Restarts:
0: [USE-VALUE] Use specified value.
1: [ABORT] abort thread (#<THREAD tid=203285 "Timer NIL" RUNNING {1001179523}>)
Backtrace:
0: (SB-VM::CALL-SYMBOL)
1: ((FLET SB-THREAD::WITH-RECURSIVE-LOCK-THUNK :IN SB-IMPL::MAKE-CANCELLABLE-INTERRUPTOR))
2: ((FLET "WITHOUT-INTERRUPTS-BODY-" :IN SB-THREAD::CALL-WITH-RECURSIVE-LOCK))
3: ((FLET "WITHOUT-INTERRUPTS-BODY-1" :IN SB-IMPL::MAKE-CANCELLABLE-INTERRUPTOR))
4: ((LAMBDA NIL :IN SB-IMPL::MAKE-CANCELLABLE-INTERRUPTOR))
5: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
6: ((FLET "WITHOUT-INTERRUPTS-BODY-" :IN SB-THREAD::RUN))
7: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
8: ((FLET "WITHOUT-INTERRUPTS-BODY-" :IN SB-THREAD::RUN))
9: (SB-THREAD::RUN)
10: ("foreign function: call_into_lisp_")
当对 lambda 表达式进行硬编码时,我没有收到任何错误,并且它按预期工作:
(defun run-timeline (timeline)
"Timeline is a plist with alternating timecodes and code to execute"
(alexandria:doplist (time form timeline)
(sb-ext:schedule-timer
(sb-ext:make-timer (lambda ()
(print "hi")
(force-output))
:thread t)
time)))
我在这里遗漏了什么?
我正在关注《光线追踪挑战》这本书。我创建了一个 vector3 和 color defstruct
(defstruct (vector3
(:conc-name nil)
(:constructor v3 (x y z w)))
(x 0.0 :type float)
(y 0.0 :type float)
(z 0.0 :type float)
(w 0.0 :type float))
(defstruct (colors
(:conc-name nil)
(:constructor colors (r g b w)))
(r 0.0 :type float)
(g 0.0 :type float)
(b 0.0 :type float)
(w 0.0 :type float))
以及其他一些函数,如比例乘数
(defun vector-scalar (s v1)
(vector3 (* s (x v1))
(* s (y v1))
(* s (z v1))
(* s (w v1))))
但是当我尝试加载文件时出现以下错误
caught WARNING:
; Derived type of COMMON-LISP-USER::V1 is
; (VALUES COMMON-LISP-USER::VECTOR3 &OPTIONAL),
; conflicting with its asserted type
; COMMON-LISP-USER::COLORS.
; See also:
; The SBCL Manual, Node "Handling of Types"
我认为程序内部的任何内容都具有局部作用域,所以我不明白为什么我认为是函数输入的内容会与 混淆defstruct
。如果我只加载向量,defstruct
则不会出现错误。
我担心的是,defstruct
我创建的任何具有四个参数的东西都会与 vector3 混淆
我不知道如何解决这个问题,因为我实际上不明白到底哪里出了问题。
我有文件R
和两个文件A
,B
。
R
始终处于加载状态。
A
xor B
的加载取决于平台特性。我有一个无论在什么平台上都应该存在的函数,调用它F
。
使用的优点/缺点是什么:
DEFGENERIC
在F
中R
,然后DEFMETHOD
在F
中A
,B
DEFUN
'F
A
B
从表面上看,它们应该是一样的。这不仅仅是个人喜好问题吗?
我目前正在采用第一种方法,因为它清楚地表明该函数是通用的并且具有实现,但我很好奇为什么与第二种方法相比它如此重要。
这个有点令人尴尬,但是我被这个问题困扰的时间比我想承认的要长。
我想生成一个宏,如果在某个现有包中找到符号,则该宏会自动隐藏该符号。我只使用 :common-lisp 包,并将从标准中隐藏几个函数。
我之前保存过一个阴影和导出符号列表,但我不想保留这些列表。相反,我更愿意从宏中隐藏符号,这样我就可以同时拥有阴影和导出声明以及定义。这看起来很简单,但是,无论我以何种方式实现它,我要么违反了包锁,要么我的符号未定义,要么其他原因。首先,这是一个包定义:
(in-package :cl-user)
(uiop:define-package :foo-package
(:nicknames :foo)
(:use :common-lisp)
(:shadow #:defun))
(in-package :foo)
测试函数不执行任何操作,只是对测试的一个小包装:
(defun make-string (length init)
(cl:make-string length :initial-element init))
我的第一次尝试是这样的:
(cl:defmacro defun (name arglist &optional docstring &rest body)
`(progn
(when (symbol-package ',name)
(shadow ',name))
(cl:defun ,name ,arglist ,docstring ,@body)
(export '(,name))))
但是,这会导致 SBCL 的包锁冲突,因此在我尝试使用 cl:defun 重新定义该函数之前,影子函数显然没有生效。
将其包装进去
(eval-when (:compile-toplevel :load-toplevel :execute)
,以使其在编译时可用并没有帮助。
另一种尝试是使用发电机:
(eval-when (:compile-toplevel :load-toplevel :execute)
(cl:defmacro defun (name args &optional docstring &rest body)
(macrolet ((export-it (name args &optional docstring &rest body)
`(progn
(when (symbol-package ',name)
(shadow ',name))
(cl:defun ,name ,args ,docstring ,@body)
(export '(,name) *package*))))
`(export-it ,name ,args ,docstring ,@body))))
这给了我 common-lisp:make-string unbound:
调试器在线程 #<THREAD "main thread" RUNNING {10044982F3}> 中的 UNBOUND-VARIABLE @10039FFD22 上调用:变量 MAKE-STRING 未绑定。
我曾尝试生成一个 lambda 并用 funcall 调用它,但也没有成功。
如果我从 repl: 手动隐藏 make-string (shadow 'make-string)
,那么我之后可以重新定义并导出 make-string 而不会出现问题。
看来我误解了一些更基本的东西。
顺便说一句,我正在阅读 M. Cracauers 的编译时编程文章,并认为将所有内容放在同一位置是一个好主意,但我认为我对宏和编译时与运行时评估的熟悉程度还不够。
我知道我可以使用 SBCL 特定的东西来临时删除包锁,但我最初用来检查符号是否在:common-lisp 包中的“shadow”和“symbol-package”或“find-package”和“find-symbol”应该更具可移植性。
我一直在尝试掌握 common-lisp 中的包系统,并且我(有点)理解这个想法。然而,像许多人一样(我搜索了许多其他类似的问题),似乎存在一些我无法完全克服的实施障碍。
所以:我试图定义一个由两个 lisp 文件组成的包。我正在使用 portacle,所有文件都位于同一目录中,包括系统定义和我编写的代码(/portacle/projects/):
ASDF 文件如下所示,它的名称只是 census-api.asd;在同一目录中有一个名为packages.lisp的包文件。
但是,当我尝试 (ql:quickload "census-api") 时,我得到“系统未找到”。
公平地说,如果我检查 Quicklisp 本地目录变量,它似乎应该可以工作:
ql:*local-project-directories*
(#P"c:/Users/Brian/portacle/projects/"
#P"c:/Users/Brian/portacle/all/quicklisp/local-projects/")
同样,我将当前路径更改为项目目录--
(setf *default-pathname-defaults* #P"c:/Users/Brian/portacle/projects/")
#P"c:/Users/Brian/portacle/projects/"
但当我尝试通过 Quicklisp 加载时,这些都不会改变“未找到系统”。我觉得我错过了某种预加载定义步骤?
接下来是什么?
我可以返回到只加载各个文件本身(它们当前使用一个“''(包内#:census-api)''”,它会出错,但我可以评论该行并直接加载),但我' d 希望能够定义系统。
编辑:好的,我直接编译了“packages.lisp”(定义如下);现在,quickload 能够执行“(ql:quickload "census-api")”,并且当通过 common lisp 用户包调用时,相关函数可用,例如 (census-api:set-fips 等)。但我仍然无法使用(包内“census-api”),如果我必须预加载所有这些文件,我觉得我一定做错了什么。
编辑2:好的,(包内:census-api)现在可以工作了,因为:census-api和“census-api”意味着不同的东西,我知道即使我并不总是理解一个与另一个的工作原理)。这解决了我当前的使用问题,但不是更广泛的问题——如何使用快速加载(或任何其他系统实用程序)来避免手动加载包?或者这只是做生意的代价?
人口普查-api.asd
(defsystem "census-api"
:description "A collection of utilities to pull Census, BLS, and Google DistanceMatrix API data.
For default use, evaluate the following --
Census: (set-fips), (set-hh-input), (print-hh-output (output-list))
BLS: (set-fips), (print-bls-data (prepare-hashed-bls-data))
Distancematric: (set-location-params), (print-dm-output (get-data (*api-response*)))"
:author "Brian LastName <[email protected]>"
:license "To be determined"
:version "0.5"
:depends-on ("dexador" "shasht")
:serial t
:components ((:file "census-api")
(:file "distancematrix-api")))
包.lisp:
;;; Packages for Census Work
(defpackage #:distancematrix-api
(:use #:cl)
(:export #:set-location-params
#:call-dm-api
#:parse-response
#:get-data
#:print-dm-output))
(defpackage #:census-api
(:use #:cl)
(:export #:set-fips
#:set-hh-output
#:print-hh-output
#:output-list
#:prepare-hashed-bls-data
#:print-bls-data))
我有这个词的两个版本hi
。
(defvar x "```hi```")
(defvar y "```
hi
```")
我还有一个正则表达式扫描仪:
(defvar scanner (cl-ppcre:create-scanner "```(.*?)```" :multi-line-mode t))
当我对 x 进行正则表达式替换时,它会按预期返回。但multi-line-mode
似乎不起作用。
(cl-ppcre:regex-replace scanner x "\\1") ;; => "hi"
(cl-ppcre:regex-replace scanner y "\\1") ;; => "```
hi
```"
我希望“```”之间的所有内容都被替换,无论字符串有多少生命。
我究竟做错了什么?
通过以下 Common Lisp 最小示例代码(来自更复杂的代码库),我收到有关行的警告,((fboundp (car ',arg)) ,arg)
但我无法解释为什么或如何避免它们。
(defmacro cond-issue (&key (arg '(a b c)))
(let ((arg-var (gensym "arg-var-")))
`(let ((,arg-var (cond ((not (listp ',arg)) (list 'arg))
((fboundp (car ',arg)) ,arg)
(t ',arg))))
`(apply #'+ ,,arg-var))))
(cond-issue :arg (e f g))
CCL 抱怨:
;Compiler warnings :
; In an anonymous lambda form: Undefined function E
; In an anonymous lambda form: Undeclared free variable F
; In an anonymous lambda form: Undeclared free variable G
SBCL 抱怨:
; in: cond-issue :arg
; (E F G)
;
; caught style-warning:
; undefined function: common-lisp-user::e
;
; caught warning:
; undefined variable: common-lisp-user::f
;
; caught warning:
; undefined variable: common-lisp-user::g
;
; compilation unit finished
; Undefined function:
; e
; Undefined variables:
; f g
; caught 2 WARNING conditions
; caught 1 STYLE-WARNING condition
CLISP 并不抱怨。
使用 SBCL,我尝试了两种方法:编译和评估代码,警告方面没有区别。 [编辑:我从答案中得知我做错了]
这将是第二种cond
形式的一个(愚蠢的)示例用例。
(cond-issue :arg (car '(e f g)))
;; ⇒ (apply #'+ e)
CCL 和 SBCL 为何抱怨?
我该如何编写代码来满足CCL和SBCL?
我正在 Common Lisp (sbcl) 中为双向链表编写一个插入函数,并将两个节点设置为彼此指向,导致结果在无限循环中打印。为什么?是什么原因导致节点无限打印呢?如何防止对象以这种方式打印?
这是一个最小的示例(全局变量用于使事情变得简单)。
(defstruct node
data
next
prev)
(defparameter *new* (make-node :data "hello"))
(defparameter *original* (make-node :data "world"))
(setf (node-prev *original*) *new*) ;; Prints fine.
(setf (node-next *new*) *original*) ;; INFINITE LOOP WHEN PRINTING!!!
setf
when 与 结合的行为let
让我感到困惑。在这里,setf
不会更改列表中的第二个值。
(defun to-temp-field (lst)
(let ((old-value (nth 2 lst))
(new-value 'hello))
(progn
(setf old-value new-value)
lst)))
但如果我不这样做let
,它会改变:
(defun to-temp-field (lst)
(let ((new-value 'hello))
(progn
(setf (nth 2 lst) new-value)
lst)))
是什么导致了这种行为?