给出以下功能,在REPL输入:
(defun animalp (thing)
(if (member thing '(dog cat snail mouse)) t))
问这个问题很简单:
(animalp 'dog)
分成包后事情变得更加复杂:
(in-package :common-lisp-user)
(defpackage :animalia
(:use :common-lisp)
(:export :animalp))
(in-package :animalia)
(defun animalp (thing)
(if (member thing '(dog cat snail mouse)) t))
现在,人们仍然可以提出同样的问题:
(animalia:animalp 'animalia::dog)
但它变得越来越混乱。 (我并不感兴趣,因为大量的动物都有问题。)基本上我想问:
(animalia:animalp 'dog)
符号(狗,猫等)没有任何属性 - 基本上我一直用它们作为字符串比较的简写:
(if (member "dog" '("dog" "cat" "mouse" "snail")
:test #'string-equal) t)
所以我的问题是围绕最佳做法。我并不喜欢使用字符串 - 特别是当(eq' dog' dog)在单个内容中如此简单时包。另一方面,我也不喜欢(defpackage ...(:export:dog:cat ...))并且需要用包装(animialia:dog等)限定每只动物的前景。最后一个明显的解决方案是制作所有动物的关键词,例如:
(if (member :dog '(:dog :cat :mouse :snail)) t)
但即使这看起来有点脏。
有哪些最佳实践解决方案可以实现我想要的,不会造成完全混乱或诉诸于幻想,丑陋和潜在脆弱解决方案的演变?
答案 0 :(得分:2)
请注意,字符串相等接受字符串指示符,并且该符号是字符串指示符。您可以非常灵活,并根据字符串相等来定义 animalp 。这确实意味着您正在进行字符串比较,但它并不要求您在代码中的其他位置使用实际字符串。
(defpackage #:animalia
(:use "COMMON-LISP"))
(in-package #:animalia)
(defun animalp (x)
(if (member x '(cat dog fish)
:test 'string-equal)
t))
(in-package #:cl-user)
(animalia::animalp :fish) ;=> T (keyword)
(animalia::animalp 'cl-user::fish) ;=> T (non-animalia package)
(animalia::animalp 'animalia::fish) ;=> T (animalia package)
(animalia::animalp '#:fish) ;=> T (no package)
(animalia::animalp "fish") ;=> T (strings, any
(animalia::animalp "FISH") ;=> T case is OK)
如果您希望快速符号相同以使 animalp 更快,那么您必须
您还可以在id256's answer中使用首先将输入转换为字符串实习生的方法,然后检查成员资格。然而,这必然涉及系统经历实习过程,这可能会破坏目的,特别是对于如此小的动物清单。它还可能会使您的 animalia 包混乱。但是,如果您愿意做类似实习的事情,那么开始使用哈希表可能会更有意义。
答案 1 :(得分:1)
带有关键字的解决方案非常标准且工作正常,但如果您想避免使用它并将符号从任何包传递到animalp
,您可以在animalia
包中实习:
(in-package :animalia)
(defun animalp (thing)
(and (member (intern (string thing) :animalia)
'(dog cat snail mouse))
t))
请注意,intern
的第二个参数(包含在符号中的PACKAGE)是可选的,默认情况下,其值为*current-package*
,在调用时为:cl-user
。要处理此问题,您可以明确使用:animalia
。