2012-06-10 82 views
5

下面的代碼在通用lisp中工作,但在emacs lisp中,它抱怨「(錯誤」方法參數中的未知類類型orc「)」。爲什麼以及如何在emacs lisp中修復它?謝謝。通用lisp和emacs lisp之間的結構差異

(defun randval (n) 
    (1+ (random (max 1 n)))) 

(defstruct monster (health (randval 10))) 

(defstruct (orc (:include monster)) (club-level (randval 8))) 

(defmethod monster-show ((m orc)) 
    (princ "A wicked orc with a level ") 
    (princ (orc-club-level m)) 
    (princ " club")) 

回答

3

事情是... defmethod需要它是一個類,而不是一個結構,在eLisp中的結構只是向量。也許你可以想出你自己的通用調度方法,但可能只是使用類而不是結構將解決它 - 類在eieio.el中實現,所以你可以看看它的內部,看看它們如何調度。或者你可以簡單地把它像:

(defun foo (monster) 
    (cond 
    ((eql (aref monster 0) 'cl-orc-struct) ...) ; this is an orc 
    ((eql (aref mosnter 0) 'cl-elf-struct) ...) ; this is an elf 
    (t (error "Not a mythological creature")))) 

這將真正取決於如何生物的許多類都在那裏,或許你能想出一些宏,隱藏條件或相當返回調用函數的基礎上類型標籤等

下面是製作自己的泛型的一個簡化想法,以防萬一你想要堅持使用結構,而且你不需要很多功能或者很樂意自己實現它:

(defvar *struct-dispatch-table* (make-hash-table)) 

(defun store-stuct-method (tag method definition) 
    (let ((sub-hash 
    (or (gethash method *struct-dispatch-table*) 
     (setf (gethash method *struct-dispatch-table*) 
      (make-hash-table))))) 
    (setf (gethash tag sub-hash) definition))) 

(defun retrieve-struct-method (tag method) 
    (gethash tag (gethash method *struct-dispatch-table*))) 

(defmacro define-struct-generic (tag name arguments) 
    (let ((argvals (cons (caar arguments) (cdr arguments)))) 
    `(defun ,name ,argvals 
     (funcall (retrieve-struct-method ',tag ',name) ,@argvals)))) 

(defmacro define-struct-method (name arguments &rest body) 
    (let* ((tag (cadar arguments)) 
    (argvals (cons (caar arguments) (cdr arguments))) 
    (generic)) 
    (if (fboundp name) (setq generic name) 
     (setq generic 
     `(define-struct-generic 
      ,tag ,name ,arguments))) 
    (store-stuct-method 
    tag name 
    `(lambda ,argvals ,@body)) generic)) 

(define-struct-method test-method ((a b) c d) 
    (message "%s, %d" a (+ c d))) 

(test-method 'b 2 3) 
"b, 5" 
+0

謝謝,我會檢查defclass。 – louxiu