LISP中的符号编程和包

时间:2015-03-12 08:22:26

标签: lisp common-lisp

给出以下功能,在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)

但即使这看起来有点脏。

有哪些最佳实践解决方案可以实现我想要的,不会造成完全混乱或诉诸于幻想,丑陋和潜在脆弱解决方案的演变?

2 个答案:

答案 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 更快,那么您必须

  1. 使用关键字,随处可访问;或
  2. 使用animalia包中定义的符号(可能在应该有权访问的包中导出并使用)。
  3. 您还可以在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