尝试调用未绑定的 fn,而我已经定义了它
Attempting to call unbound fn, while I have defined it
我正在尝试将 SICP 的 meta-circular evaluator 转换为 Clojure。在 setup-environment
中,对 extend-environment
的调用无法编译,因为我收到错误 "Attempting to call unbound 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
方法时,我得到以下错误:
- 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
我想我没有提供正确类型的参数或者我没有创建正确类型的函数。我尝试了匿名方法的各种变体并在括号中传递或不传递,但我无法编译它。
有谁知道这个错误的原因是什么,我该如何解决?
的定义
(def primitive-procedure-names
#(map [first
primitive-procedures]))
很可能没有按照您的意图进行。正如所写,它定义了一个不带参数的函数和 return 的转换器(它是一个函数),如果应用于序列,它将用值 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 是一个 return 函数,如果您调用该函数 return 一个 return 初始环境未被调用修改的函数定义变量。在 Clojure 中,集合类型是不可变的,因此如果您想对集合进行多项更改,则有必要将添加第一个的结果链接到添加第二个的输入,然后 return 添加第二个的结果一:
(add-second (add-first initial-value))
也可以这样写:
(-> initial-value
add-first
add-second)
这只是上面示例的 shorthand。
我正在尝试将 SICP 的 meta-circular evaluator 转换为 Clojure。在 setup-environment
中,对 extend-environment
的调用无法编译,因为我收到错误 "Attempting to call unbound 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
方法时,我得到以下错误:
- 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
我想我没有提供正确类型的参数或者我没有创建正确类型的函数。我尝试了匿名方法的各种变体并在括号中传递或不传递,但我无法编译它。
有谁知道这个错误的原因是什么,我该如何解决?
(def primitive-procedure-names
#(map [first
primitive-procedures]))
很可能没有按照您的意图进行。正如所写,它定义了一个不带参数的函数和 return 的转换器(它是一个函数),如果应用于序列,它将用值 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 是一个 return 函数,如果您调用该函数 return 一个 return 初始环境未被调用修改的函数定义变量。在 Clojure 中,集合类型是不可变的,因此如果您想对集合进行多项更改,则有必要将添加第一个的结果链接到添加第二个的输入,然后 return 添加第二个的结果一:
(add-second (add-first initial-value))
也可以这样写:
(-> initial-value
add-first
add-second)
这只是上面示例的 shorthand。