4845


CommonLispの勉強のため、CLOS(Common Lisp Object System)を利用してスタック構造を実装しているところです。

スタック構造なので、メソッド名に`pop`と`push`というのを定義したいのですが、CLOSの仕様上、そのまま定義しようとすると、既にCommon
Lispの組み込み関数として定義されている`pop`と`push`と被ってしまいます。このとき、メソッド名をリネームして衝突を回避することは可能だと思いますが、それよりは`pop`・`push`のメソッド名のまま利用したいと考えています。このとき、Common
Lispではどのように解決するのが望ましいと言えるのでしょうか?

汚いですが、具体的なコードも掲載しておきます:

[code]

      (defclass stack () ((state :accessor state :initform '())))
      (defmethod push ((stack-obj stack) elem)
        (let ((new-stack
               (if (state stack-obj) (cons elem (state stack-obj)) (list elem))))
          (setf (state stack-obj) new-stack)))
      (defmethod pop ((stack-obj stack))
        (let ((pop-stack (car (state stack-obj))))
          (progn (setf (state stack-obj) (cdr (state stack-obj)))
                 pop-stack)))
    
[/code]

また、`sbcl`処理系を利用した場合のエラーメッセージは以下のようになります:

[code]

      Unhandled SYMBOL-PACKAGE-LOCKED-ERROR in thread #<SB-THREAD:THREAD
                                                        "main thread" RUNNING
                                                         {10039B6833}>:
        Lock on package COMMON-LISP violated when proclaiming PUSH as a function
        while in package COMMON-LISP-USER.
      See also:
        The SBCL Manual, Node "Package Locks"
        The ANSI Standard, Section 11.1.2.1.2
    
[/code]


CC BY-SA 3.0
2015-01-19T00:59:09.027
4803
2015-01-19T11:44:14.153
2015-01-19T11:44:14.153
939
question
common-lisp sbcl
CLOSを利用した場合に、defmethodで定義したメソッドが組み込み関数と被るときの対処法


専用のパッケージを作ってみてはいかがですか。例えば、`my-stack` というパッケージを作ってみます。

[code]

    (defpackage my-stack
      (:use :common-lisp)
      (:shadow :common-lisp push pop)
      (:export stack state push pop))
    
    (in-package :my-stack)
    
    (defclass stack () ((state :accessor state :initform '())))
    
    (defmethod push ((stack-obj stack) elem)
      (let ((new-stack
             (if (state stack-obj) (cons elem (state stack-obj)) (list elem))))
        (setf (state stack-obj) new-stack)))
    
    (defmethod pop ((stack-obj stack))
      (let ((pop-stack (car (state stack-obj))))
        (progn (setf (state stack-obj) (cdr (state stack-obj)))
               pop-stack)))
    
[/code]

これを、例えば `my-stack.cl` というファイルに保存して、

[code]

    $ sbcl --load my-stack.cl
    
[/code]

ロードします。そして、`my-stack` パッケージに移ります

[code]

    * (in-package :my-stack)
    #<PACKAGE "MY-STACK">
    
    * (setq st (make-instance 'stack))
    
    * (push st "foo")
    ("foo")
    * (push st "bar")
    ("bar" "foo")
    * (push st "baz")
    ("baz" "bar" "foo")
    * (state st)
    ("baz" "bar" "foo")
    
    * (pop st)
    "baz"
    * (state st)
    ("bar" "foo")
    
[/code]

もしも、デフォルトパッケージにある `push` などを使いたい場合は、パッケージ名を指定して使います。

[code]

    * (setq lst '())
    * (common-lisp-user::push "foo" lst)
    ("foo")
    
[/code]


CC BY-SA 3.0
2015-01-19T11:12:57.190
4845
2015-01-19T11:18:11.097
2015-01-19T11:18:11.097
4803
answer