2

Clojure では、ハッシュマップとベクトルは を実装invokeしているため、関数として使用できます。たとえば、

(let [dict {:species "Ursus horribilis"
            :ornery :true
            :diet "You"}]
  (dict :diet))

lein> "You"

または、ベクトルの場合、

(let [v [42 613 28]]
  (v 1))

lein> 613

実装することで、Clojure で呼び出し可能なオブジェクトを作成できますIFn。私は Common Lisp に慣れていません -呼び出し可能なオブジェクトは可能ですか? もしそうなら、それを実装するには何が必要ですか? 次のようなことができるようになりたいです

(let ((A (make-array (list n n) ...)))
   (loop for i from 0 to n
         for j from 0 to m
      do (setf (A i j) (something i j)))
   A)

コードが散らばっているのではなくaref。同様に、辞書などの他のデータ構造のエントリにも同じ方法でアクセスできればすばらしいと思います。

Lisp/Scheme の関数オブジェクトに関するwiki エントリを見てきましたが、別の関数名前空間を持つと CL の問題が複雑になるようですが、Scheme ではクロージャでこれを行うことができます。

4

3 に答える 3

4

やりたいことを正確に行う方法はないかもしれませんが、似たようなことをハックする方法がいくつかあります。1 つのオプションは、関数を呼び出し可能なオブジェクトにローカルにバインドできるようにする新しいバインディング フォーム with-callable を定義することです。たとえば、

(with-callable ((x (make-array ...)))
  (x ...))

にほぼ等しい

(let ((x (make-array ...)))
  (aref x ...))

with-callable の可能な定義は次のとおりです。

(defmacro with-callable (bindings &body body)
  "For each binding that contains a name and an expression, bind the
   name to a local function which will be a callable form of the
   value of the expression."
  (let ((gensyms (loop for b in bindings collect (gensym))))
    `(let ,(loop for (var val) in bindings
                 for g in gensyms
                 collect `(,g (make-callable ,val)))
       (flet ,(loop for (var val) in bindings
                    for g in gensyms
                    collect `(,var (&rest args) (apply ,g args)))
         ,@body))))

あとは、オブジェクトにアクセスするためのクロージャーを返す make-callable のさまざまなメソッドを定義するだけです。たとえば、配列に対してそれを定義するメソッドは次のとおりです。

(defmethod make-callable ((obj array))
  "Make an array callable."
  (lambda (&rest indices)
    (apply #'aref obj indices)))

この構文は見栄えが悪いので、マクロを使用してよりきれいにすることができます。

(defmacro defcallable (type args &body body)
  "Define how a callable form of TYPE should get access into it."
  `(defmethod make-callable ((,(car args) ,type))
     ,(format nil "Make a ~A callable." type)
     (lambda ,(cdr args) ,@body)))

配列を呼び出し可能にするには、次を使用します。

(defcallable array (obj &rest indicies)
  (apply #'aref obj indicies))

ずっといい。これで、オブジェクトへのアクセスを可能にするローカル関数を定義するフォーム with-callable と、他の型の呼び出し可能なバージョンを作成する方法を定義できるマクロ defcallable ができました。この戦略の欠点の 1 つは、オブジェクトを callable にするたびに with-callable を明示的に使用する必要があることです。


呼び出し可能なオブジェクトに似た別のオプションは、ssyntaxにアクセスする Arc の構造です。基本的に x.5 は、x のインデックス 5 の要素にアクセスします。Common Lisp でこれを実装することができました。私が書いたコードはここここで見ることができます。私はそれのテストも持っているので、ここでそれがどのように見えるかを見ることができます.

私の実装がどのように機能するかは、本体内のすべてのシンボルを調べ、それらの一部に対してマクロとシンボルマクロを定義するマクロ w/ssyntax を作成したことです。たとえば、x.5 のシンボル マクロは (get x 5) になります。ここで、get は構造体にアクセスするために定義した汎用関数です。これの欠点は、ssyntax を使用したい場合は常に w/ssyntax を使用する必要があることです。幸いなことに、defun のように機能するマクロ def 内にそれを隠すことができます。

于 2015-01-17T16:03:14.363 に答える
0

私は、Rainer Joswig のアドバイスに同意します。Common Lisp のやり方に慣れる方がよいでしょう。ちょうど、Common Lisp プログラマーが Clojure に切り替えるときに、Clojure のやり方に慣れるほうがよいのと同じです。ただし、malisper の洗練された回答が示すように、必要なことの一部を実行することは可能です。以下は、より単純な戦略の始まりです。

(defun make-array-fn (a) 
  "Return a function that, when passed an integer i, will 
  return the element of array a at index i."
  (lambda (i) (aref a i)))

(setf (symbol-function 'foo) (make-array-fn #(4 5 6)))

(foo 0) ; => 4
(foo 1) ; => 5
(foo 2) ; => 6

symbol-functionシンボル の関数セルにアクセスし、によって作成された関数オブジェクトをそこfooに入れます。この関数は関数セルにあるため、リストの関数位置で使用できます。必要に応じて、次のように操作全体をマクロにまとめることができます。setfmake-array-fnfoo

(defmacro def-array-fn (sym a)
  "Define sym as a function that is the result of (make-array-fn a)."
  `(setf (symbol-function ',sym)
         (make-array-fn ,a)))

(def-array-fn bar #(10 20 30 40))

(bar 0) ; => 10
(bar 1) ; => 20
(bar 3) ; => 40

もちろん、このように定義された「配列」はもはや配列のようには見えません。CL の印刷ルーチンを使って何か面白いことができると思います。配列の値を設定できるようにすることも可能ですが、これにはおそらく別のシンボルが必要になります。

于 2015-01-18T07:26:55.667 に答える