2016-04-05 10 views
1

Я пытаюсь преобразовать SICP meta-circular evaluator в Clojure. В setup-environment вызов extend-environment не скомпилируется, потому что я получаю сообщение об ошибке «Попытка вызова несвязанного fn». Вот часть кода:Попытка вызвать несвязанный 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])) 

вероятно, не делать то, что вы собираетесь. Как написано, это определяет функцию, которая не принимает никаких аргументов и возвращает преобразователь (который является функцией), который, если применяется к последовательности, заменяет значения 0 и 1 для функций first и primitive-procedures соответственно. Я продемонстрирую первую с функциями, а затем со значениями чисел, чтобы сделать то, что происходит более ясно (надеюсь):

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 типы коллекций неизменяемы, поэтому, если вы хотите внести несколько изменений в коллекцию, необходимо связать результат добавления первого в значение ввода второго, затем вернуть результат добавления второго:

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

, который также может быть записана следующим образом:

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

который является просто сокращение для приведенного выше примера.