1

clojure 的新手,尝试为布尔表达式求值器编译以下代码

;core.clj
(ns my-app.core
  (:gen-class))

(defn t [& args] (if (empty? args) t
                 ((first args) t (first (rest args)))))

(defn f [& args] (if (empty? args)  f
                 ((first args)  f (first (rest args)))))

(defn | [cond1 cond2] (if (= cond1 t) t
                      (if (= cond2 t) t f)))

(defn & [cond1 cond2] (if (= cond1 f) f
                      (if (= cond2 f) f t)))

(defn ! [& args] (if (= (first args) t)
               (apply f (rest args))
               (if ( = (first args) f)
                 (apply t (rest args))
                 (! (apply (first args) (rest args))))))


(defn -main [& args]
 (loop [line (read-line)]
   (do
      (println (eval (read-string (apply str "" (interpose \space  (seq (str "(" line ")")))))))
  (if (= (count line) 1) nil (recur (read-line))))))

每次我执行“lein run”并输入字符串“(t|t)=t”时,都会出现以下错误

Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: t in this context

但是,如果我在“src/my_app/”目录中打开一个新的 nrepl,然后输入命令

(-main)

我得到正确的字符串和结果

( ( t | t ) = t )
true

我应该注意,在运行 lein run

其他字符串字符串 "+ 1 2 3 4 5 6" 将正确评估,但由于某种原因它无法识别函数 (t ...)

有人知道发生了什么吗?

4

1 回答 1

3

eval使用当前(线程绑定)值*ns*来确定您当前“在”哪个命名空间,它控制如何解析不合格符号。在运行后的 repl 中(ns my-app.core ...),您位于my-app.core名称空间中,因此 eval 找到t您在那里定义的。但是,即使您仍然在 中定义,编译后tmy-app.core当您的程序开始运行时,您仍处于user命名空间中并且 eval 无法找到t

因此,您需要做的就是将您的命名空间更改-main为 be my-app.core,使用binding如下:

(defn -main [& args]
   (绑定 [*ns* (the-ns 'my-app.core)]
    (循环[行(读取行)]
      (println (eval (read-string (apply str (interpose \space (str "(" line ")"))))))
      (when-not (= (count line) 1)
        (recur (read-line))))))
于 2013-03-26T14:46:24.130 回答