如何检查Common Lisp中的两种类型是否相同?

如何检查Common Lisp中的两种类型是否相同?,lisp,common-lisp,Lisp,Common Lisp,我正在学习CommonLisp,现在正试图复制C++的boost的词法字符串。但是在CL中找不到比较类型的方法 < C++版本看起来像这个< /P> 样板 ret_type词法_castcont std::string&val { 如果constexpr std::是相同的 返回val==true; //否则我不在乎 } 到目前为止,我使用equal来比较类型,得到了以下Lisp代码。我认为这是可行的,因为Lisp对数据和代码漠不关心 defun词法_castret _类型val 如果equal

我正在学习CommonLisp,现在正试图复制C++的boost的词法字符串。但是在CL中找不到比较类型的方法

< C++版本看起来像这个< /P> 样板 ret_type词法_castcont std::string&val { 如果constexpr std::是相同的 返回val==true; //否则我不在乎 } 到目前为止,我使用equal来比较类型,得到了以下Lisp代码。我认为这是可行的,因为Lisp对数据和代码漠不关心

defun词法_castret _类型val 如果equal ret_type“布尔等式值为真 ; 否则就不要这样了 但SBCL会产生错误:

; in: DEFUN LEXICAL_CAST
;     #'BOOLEAN
; 
; caught WARNING:
;   The function BOOLEAN is undefined, and its name is reserved by ANSI CL so that
;   even if it were defined later, the code doing so would not be portable.
; 
; compilation unit finished
;   Undefined function:
;     BOOLEAN
;   caught 1 WARNING condition

typep也没有帮助,因为它将对象的类型与另一种类型进行比较。不直接比较。我搜索了Lisp教程和手册,但没有成功。我该怎么做呢?

我的错。我在发布问题后立即发现了问题。那辆车不应该在那里

defun词法_castret _类型val 如果equal ret_type“布尔等式值为真 ; 否则就不要这样了
我的错。我在发布问题后立即发现了问题。那辆车不应该在那里

defun词法_castret _类型val 如果equal ret_type“布尔等式值为真 ; 否则就不要这样了 CommonLisp定义了比较类型。使用该函数,可以定义类型相等比较函数:

(defun type-equal (t1 t2)
  (and (subtypep t1 t2)
       (subtypep t2 t1)))
(defun gen-type-cast (return-type value)
  (let ((f (assoc return-type *type-cast* :test #'type-equal)))
    (if f (funcall (cdr f) value) (error 'cast-error))))
例如,有不同的方式编码布尔类型,但它们覆盖相同的值集,因此它们相等:

(type-equal '(member t nil) '(or (eql t) (eql nil)))
=> T, T
还有一个函数以有限的方式允许将值转换为另一种类型。然而,这是不可扩展的

简单铸造 让我们首先为不知道如何将值强制转换为目标类型的情况定义一个新条件。为了简单起见,此错误没有关联的数据:

(define-condition cast-error (error) ())
然后,词法转换的严格但简单的定义可以是:

我将cond表单包装为强制表单,以检查内部结果是否为适当的返回类型。这有助于检测实现错误

内部表单对返回类型cond和值的类型typecases执行多次分派。例如,您可以将字符串转换为布尔值:

(lexical-cast '(member t nil) "true")
T
(lexical-cast 'bit t)
1
假设我们遵循C约定0为false,下面是一个数字转换,注意布尔类型的表达方式不同:

(lexical-cast '(or (eql t) (eql nil)) 0)
NIL
还请注意,CommonLisp允许您定义范围。这里我们有一个错误,因为从字符串读取的值超出了例外范围小心:从字符串读取可能对某些输入不安全,但这超出了这里的范围

(lexical-cast '(integer 0 10) "50")
;; error from COERCE

(lexical-cast '(integer 0 10) "5")
5
下面是另一个示例,从布尔值转换为实数的子类型:

(lexical-cast '(member t nil) "true")
T
(lexical-cast 'bit t)
1
可伸缩铸件 为了有一个通用的可扩展词法转换,比如,您需要维护不同类型的转换函数表,同时确保始终选择与返回类型匹配的最接近的类型

一种非常简单的方法是为某些专用返回类型定义单独的通用转换函数:

;; can be extended for other classes of values
(defgeneric cast-to-boolean (value)
  (:method ((v symbol))  v)
  (:method ((v integer)) (eql v 1))
  (:method ((v string))  (string= v "true")))
然后,维护从类型到转换函数的映射:

;; usually this is hidden behind user-friendly macros

(defvar *type-cast* nil)  

;; this could be written instead (set-cast 'boolean #'cast-to-boolean)
;; for example, but here we just set the list directly.

(setf *type-cast*
      (acons 'boolean #'cast-to-boolean *type-cast*))
然后,您有一个单一的强制转换函数,用于查找与返回类型相等的第一个类型,并调用关联的函数:

(defun type-equal (t1 t2)
  (and (subtypep t1 t2)
       (subtypep t2 t1)))
(defun gen-type-cast (return-type value)
  (let ((f (assoc return-type *type-cast* :test #'type-equal)))
    (if f (funcall (cdr f) value) (error 'cast-error))))
例如:

(gen-type-cast '(member t nil) "true")
T
另见 该系统有助于分析和简化类型表达式。

通用Lisp定义用于比较类型。使用该函数,可以定义类型相等比较函数:

(defun type-equal (t1 t2)
  (and (subtypep t1 t2)
       (subtypep t2 t1)))
(defun gen-type-cast (return-type value)
  (let ((f (assoc return-type *type-cast* :test #'type-equal)))
    (if f (funcall (cdr f) value) (error 'cast-error))))
例如,有不同的方式编码布尔类型,但它们覆盖相同的值集,因此它们相等:

(type-equal '(member t nil) '(or (eql t) (eql nil)))
=> T, T
还有一个函数以有限的方式允许将值转换为另一种类型。然而,这是不可扩展的

简单铸造 让我们首先为不知道如何将值强制转换为目标类型的情况定义一个新条件。为了简单起见,此错误没有关联的数据:

(define-condition cast-error (error) ())
然后,词法转换的严格但简单的定义可以是:

我将cond表单包装为强制表单,以检查内部结果是否为适当的返回类型。这有助于检测实现错误

内部表单对返回类型cond和值的类型typecases执行多次分派。例如,您可以将字符串转换为布尔值:

(lexical-cast '(member t nil) "true")
T
(lexical-cast 'bit t)
1
假设我们遵循C约定0为false,下面是一个数字转换,注意布尔类型的表达方式不同:

(lexical-cast '(or (eql t) (eql nil)) 0)
NIL
还请注意,CommonLisp允许您定义范围。这里我们有一个错误,因为从字符串读取的值超出了例外范围小心:从字符串读取可能对某些输入不安全,但这超出了这里的范围

(lexical-cast '(integer 0 10) "50")
;; error from COERCE

(lexical-cast '(integer 0 10) "5")
5
下面是另一个示例,从布尔值转换为实数的子类型:

(lexical-cast '(member t nil) "true")
T
(lexical-cast 'bit t)
1
可伸缩铸件 为了有一个通用的可扩展词法转换,比如,您需要维护不同类型的转换函数表,同时确保始终选择与返回类型匹配的最接近的类型

< p> 一种非常简单的方法是为某些专用返回类型定义单独的通用转换函数:

;; can be extended for other classes of values
(defgeneric cast-to-boolean (value)
  (:method ((v symbol))  v)
  (:method ((v integer)) (eql v 1))
  (:method ((v string))  (string= v "true")))
然后,维护从类型到转换函数的映射:

;; usually this is hidden behind user-friendly macros

(defvar *type-cast* nil)  

;; this could be written instead (set-cast 'boolean #'cast-to-boolean)
;; for example, but here we just set the list directly.

(setf *type-cast*
      (acons 'boolean #'cast-to-boolean *type-cast*))
然后,您有一个单一的强制转换函数,用于查找与返回类型相等的第一个类型,并调用关联的函数:

(defun type-equal (t1 t2)
  (and (subtypep t1 t2)
       (subtypep t2 t1)))
(defun gen-type-cast (return-type value)
  (let ((f (assoc return-type *type-cast* :test #'type-equal)))
    (if f (funcall (cdr f) value) (error 'cast-error))))
例如:

(gen-type-cast '(member t nil) "true")
T
另见 该系统有助于分析和简化类型表达式