Попытка вызвать несвязанный fn, пока я его определил

Я пытаюсь преобразовать мета-циркулярный оценщик SICP в Clojure. В setup-environment вызов 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. Вызвано java.lang.IllegalStateException
    Попытка вызвать несвязанный fn:
    # 'Схема-оценщик / простираться-среда
    Var.java: 43 clojure.lang.Var $ Unbound / throwArity
    AFn.java: 40 clojure.lang.AFn / invoke
    схема-оценки.clj: 277 схема-оценки /eval7808

Я думаю, что я не предоставляю правильный тип параметров, или я не создал правильный тип функции. Я пробовал различные варианты анонимных методов и передачи в скобках или без, но я не получаю его для компиляции.

Кто-нибудь знает, в чем причина этой ошибки и как ее можно исправить?

1 ответ

Решение

Определение

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

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

Другие вопросы по тегам