2016-04-05 12 views
1

私はSICPのmeta-circular evaluatorをClojureに変換しようとしています。 setup-environmentでは、「アンバウンドfnを呼び出そうとしています」というエラーが表示されるため、extend-environmentへの呼び出しはコンパイルされません。ここでは、コードの一部です:バインドされていないfnを定義しようとしましたが、

(... loads of methods for creating and managing environment list) 

(def primitive-procedures 
    (list (list 'car first) 
     (list 'cdr rest) 
     (list 'cons conj) ;; TODO: reverse 
     (list 'null? nil?) 
     (list 'list list) 
     (list '+ +) 
     (list '- -) 
     (list '* *) 
     (list '/ /) 
     ;;  more primitives 
     )) 

(def primitive-procedure-names 
    #(map [first 
     primitive-procedures])) 

(def primitive-procedure-objects 
    (fn [] (map (fn [p] (list 'primitive (second p))) 
       primitive-procedures))) 

(def the-empty-environment '()) 

(defn extend-environment [vars vals base-env] 
    (if (= (count vars) (count vals)) 
    (conj base-env (make-frame vars vals)) 
    (if (< (count vars) (count vals)) 
     (throw (Throwable. "Too many arguments supplied") vars vals) 
     (throw (Throwable. "Too few arguments supplied") vars vals)))) 

;; Added # in front here so it could be called (???) 
(defn setup-environment [] 
    #(let [initial-env 
     (extend-environment (primitive-procedure-names) 
          (primitive-procedure-objects) 
          the-empty-environment)] ;; <= that does not work 
    (define-variable! 'true true initial-env) 
    (define-variable! 'false false initial-env) 
    initial-env))) 

;; Method for interacting with the evaluator: 

(defn driver-loop [] 
    (prompt-for-input input-prompt) 
    (let [input (read)] 
    (let [output (m-eval input the-global-environment)] 
     (announce-output output-prompt) 
     (user-print output))) 
    (driver-loop)) 

(...) 

(def the-global-environment (setup-environment)) 
(driver-loop) 

そして私は、私は次のエラーを取得するextend-environment方法を評価するとき:

  1. Caused by java.lang.IllegalStateException
    Attempting to call unbound fn:
    #'scheme-evaluator/extend-environment
    Var.java: 43 clojure.lang.Var$Unbound/throwArity
    AFn.java: 40 clojure.lang.AFn/invoke
    scheme-evaluator.clj: 277 scheme-evaluator/eval7808

を私はパラメータの右の種類を提供していないですか、私が作成していないと思います適切なタイプの機能。私は匿名メソッドのさまざまなバリエーションを試して、カッコかどうかを渡しましたが、私はそれをコンパイルすることはありません。

誰もがこのエラーの理由を知っていますが、どうすれば修正できますか?

答えて

4

(def primitive-procedure-names 
    #(map [first 
     primitive-procedures])) 

の定義は、おそらくあなたが意図し何をしません。書かれているように、これは、引数をとらない関数を定義し、シーケンスに適用された場合、それぞれ関数firstprimitive-proceduresの値0と1を代入するトランスデューサ(関数)を返します。私は(たぶん)より明確に何が起こっているかを作るために数字の値で、その後の関数として最初に説明します:

user> (into [] (map [first 'example]) [0 1]) 
[#function[clojure.core/first--4339] example] 
user> (into [] (map [1 2]) [0 1]) 
[1 2] 

おそらくあなたは

(def primitive-procedure-names 
(map first primitive-procedures)) 

を望んでいたと私は定義するためのdefnフォームを使用して提案することができますあなたが本当に強い理由を持っていなければ、値を定義するためのdef形式と関数を使用します。

setup-environmentは、その関数を呼び出すと、define-variableの呼び出しによって変更されていない初期環境を返す関数を返す関数です。 Clojureではコレクションの型は不変なので、コレクションをいくつか変更したい場合は、最初のコレクションを追加して2番目のコレクションを追加した結果をチェーンし、2番目のコレクションを追加した結果を返す必要があります。

(-> initial-value 
    add-first 
    add-second) 

上記例えば単に速記である。また、このように書くことができる

(add-second (add-first initial-value)) 

関連する問題