2015-04-03 94 views
2
(defmacro test (&key list &environment env) 
    (typecase (get-type list env) 
    (list `(do-something (list ,@list))) 
    (integer `(do-something (list ,list ,list ,list))))) 

(test :list '(1 2 3)) ; => (do-something (list 1 2 3)) 
(test :list (* 1 2)) ; => (do-something (list (* 1 2) (* 1 2) (* 1 2))) 

是否可以在宏展开时获取list的类型? (我称为get-type获取宏中的类型信息

它不适用于评估,因为此时变量可能不存在,也可能会更改其他一些值,但不应更改。

或者我应该让我的宏扩展是一种形式,也称为typecase?

回答

2

除了Rainer's excellent answer,请注意,Common Lisp包含功能constantp,它具有表单和环境。这不会”涵盖所有情况下,因为有人可能会用一个变量而不是一个恒定的形式调用宏,但你得到恒定的形式的情况下,你可以在编译时检查它的类型:

(defmacro foo (arg &environment environment) 
    (if (constantp arg environment) 
     (typecase arg 
     (string 'string-expansion) 
     (vector 'vector-expansion) 
     (number 'number-expansion) 
     (t 'constant-but-other-type-expansion)) 
     'nonconstant-expansion)) 
现在

CL-USER> (macroexpand '(foo "hello")) 
STRING-EXPANSION 
T 
CL-USER> (macroexpand '(foo #(1 2 3))) 
VECTOR-EXPANSION 
T 
CL-USER> (macroexpand '(foo 42)) 
NUMBER-EXPANSION 
T 
CL-USER> (macroexpand '(foo 'something-else)) 
CONSTANT-BUT-OTHER-TYPE-EXPANSION 
T 
CL-USER> (macroexpand '(foo bar)) 
NONCONSTANT-EXPANSION 
T 

,这可能看起来有点迂回,但它可以是在一些地方非常有用。

或者我应该让我的宏扩展是一种形式,这也叫 典型案例?

如果你的序列操作函数开源实现看看你可能会发现一些很有趣代码示例。许多Common Lisp函数(例如,减少)采用序列,并且这些可以是列表或向量。遗憾的是,的代码实施减少这两种类型有效地不同。例如,看看SBCL's sequence functions。你会开始感受到他们如何处理这个问题。您可能还想看看编译器宏。

3

大多数Lisp方言可以看作动态类型。 Common Lisp也不例外。添加了类型和类型声明以允许在运行时处理类型:用于运行时类型检查和运行时类型调度。它还允许Common Lisp实现在编译时使用类型信息来生成更快的代码。使用类型信息进行编译时类型检查或在宏中的用户级别不是目标。尽管至少早期CMUCL(以及后来的SBCL和Scieneer CL)使用类型声明和类型推断来进行一些编译时类型检查。大多数其他实现不会进行编译时类型检查,而有一些实现类型推断。

请注意,您可以在运行时添加或重新定义类型。另外,类型层次结构可以在运行时更改(例如,类层次结构)。

如果你有一个实际的对象,你可以确定Lisp系统认为它在编译时的类型。

但是什么是函数返回值的类型?信息可能来自类型声明或类型推断。后者在Common Lisp中不可移植 - 可能有实现特定的方式从类型推断中获取信息或从库中使用类型推断器。

有关函数类型声明的信息Common Lisp的某些实现提供了一个函数FUNCTION-INFORMATION(最初为ANSI CL提出,但没有将其纳入实际标准)。

在这里,在LispWorks 6.1:

CL-USER 42 > (compile (defun foo() (the fixnum 3))) 
FOO 
NIL 
NIL 

CL-USER 43 > (declaim (ftype (function() fixnum) foo)) 
T 

CL-USER 44 > (function-information 'foo) 
:FUNCTION 
NIL 
((FTYPE FUNCTION NIL FIXNUM)) 

VARIABLE-INFORMATION见。 FUNCTION-INFORMATIONVARIABLE-INFORMATION也记录在CLtL2中,但不是Common Lisp Hyperspec(因为它们不在标准中)。

通常在宏扩展时使用这些类型的信息操作会打开一整罐蠕虫。对于基本用途,我会建议考虑运行时类型,并创建代码运行时类型调度 - 除非在编译时确实需要类型信息。