2016-04-05 18 views
1

tanımladım SICP'nin meta-circular evaluator numarasını Clojure'a dönüştürmeye çalışıyorum. setup-environment'da extend-environment çağrısı, "Unbound fn çağrılıyor" hatası aldığım için derlenmiyor. İşte kod parçası:Tanımsız fn aramayı denerken,

(... 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) 

Ve aşağıdaki hatayı alıyorum extend-environment yöntemi değerlendirirken:

  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

Ben parametrelerin doğru türde sağlayan değilim düşünüyorum ya da ben yarattım doğru işlev türü. Anonim yöntemlerin çeşitli varyasyonlarını denedim ve parantez içinde veya olmadan geçtim, ama derlemeyi anlamıyorum.

Herkes bu hatanın sebebinin ne olduğunu biliyor mu ve nasıl düzeltebilirim?

cevap

4

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

tanımı olasılıkla niyetinde ne yapmaz. Yazıldığı gibi bu, hiçbir argüman almayan ve bir sıraya uygulandığında sırasıyla first ve primitive-procedures işlevleri için 0 ve 1 değerlerini alacak olan dönüştürücüyü (bir işlev olan) döndüren bir işlevi tanımlar. Ben daha net (umarım) neler olduğunu yapmak için sayıların değerleri ile ilk fonksiyonları ile ve daha sonra açılayacağız:

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

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

istedi Ve tanımlamak için defn formu kullanarak önerebilir Fonksiyonlar ve gerçekten güçlü bir nedeniniz olmadığı sürece değerleri tanımlamak için def formu.

setup-environment, bu işlevi çağırırsanız, bir işlev döndüren bir işlevi döndürür; bu işlev, çağrının değişkeni için çağrılar tarafından değiştirilmeyen ilk ortamı döndüren bir işlev döndürür. Clojure'da koleksiyon türleri değişmez, dolayısıyla bir koleksiyonda birkaç değişiklik yapmak istiyorsanız, ilkini ekleme işleminin sonucunu ikinci ekleme işleminin eklenmesi sonucunu zincirlemeniz gerekir, ardından ikinci olanı ekleme sonucunu döndürün:

Ayrıca böyle yazılabilir
(add-second (add-first initial-value)) 

:

yukarıdaki örneğin sadece bir kısaltmadır
(-> initial-value 
    add-first 
    add-second) 

.