无法在 class 路径上找到应用 /clojure/core/vector__init.class 或 apply/clojure/core/vector.clj

Could not locate apply /clojure/core/vector__init.class or apply/clojure/core/vector.clj on classpath

当我尝试 运行 我的程序时出现以下错误:Exception in thread "main" java.io.FileNotFoundException: Could not locate apply /clojure/core/vector__init.class or apply/clojure/core/vector.clj on classpath: , compiling:(erbium/compile.clj:1:1)。它似乎指向下面的文件并建议我需要将 clojure.core/vector 放入我的依赖项中。默认不包含吗?

(ns erbium.compile
    (require `[clojure.string :as string])
)

(defn produce-out "Convert 'command %1 %2 %3' with stack [5 6 7] to 'command 5 6 7'" [word stack definitions]
    (let [
            code (definitions word) ; dictionary/hash lookup. eg. "println" -> "echo "
            replacement (fn [match] (-> match second Long/parseLong dec stack str))
         ]
        ; evaluate arguments. eg. "echo %1"
        ;                         stack=["blah"]
        ;                         -> "echo blah"
        (string/replace code #"%(\d)" replacement)
    )
)

(defn parse-word "Verifies that word is in defintitions and then returns (produce-out word stack)" [word stack definitions]
    (if (some #{word} (keys definitions))
        (produce-out word stack)
    )
)

(defn compile "Main compile function" [code]
    (let [
            split-code (string/split code #"\s")
            definitions {
                "println" "echo %1"
                "+" "%1 + %2"
                "-" "%1 - %2"
            }
            stack []
        ]

        (for [word [split-code]]
            (if (integer? (read-string word))
                (do
                    (println "Found integer" word)
                    (def stack (conj stack (read-string word)))
                    (println "Adding to argument stack:" stack)
                )

                ; else
                (do
                    (parse-word word stack definitions)
                    (def stack [])
                )
            )
        )
    )
)

此文件由核心文件通过 (load "compile") 加载,如果有差异的话。

我看到的第一个错误是:

(require `[clojure.string :as string])

应该是这样的:

(:require [clojure.string :as string])

在常规的 clojure 源文件中。这为我修好了。

也就是说,这里有一些一般性建议:

  1. 有很多格式"mistakes"。当然,您可以按照自己的意愿格式化代码,但是,如果您坚持基本的格式化原则,其他人会更容易遵循。这是其中的一个很好的集合:https://github.com/bbatsov/clojure-style-guide 大多数编辑器都实现了一些格式化工具。
  2. split-code (str/split code #"\s") 这不会按照您的要求工作 [clojure.string :as string] 所以将其更改为: split-code (string/split code #"\s")
  3. 我不确定 (load ...) 以及通常在哪种情况下使用它。但是,对于开始学习 clojure,我推荐 Lighttable,因为它内置了即时反馈,这在学习新东西时非常有价值。

为了扩展答案,"require" 出现在名称空间声明 "ns" 中。 ns 实际上是一个宏,它扩展为一系列语句来创建命名空间,并进行一些设置。

此宏将 (:require ...) 之类的语句视为对名称为 require 的函数的调用,并自动引用任何后续参数。由于您自己指定了引号:

(ns erbium.compile
  (require '[clojure.string :as string]))

然后结果最终被双引号引用,对 require 的调用最终成为:

... (require (quote (quote [clojure.string :as string])))

所以它最终尝试加载一个名为 "quote" 的名称空间,后跟一个语法上错误位置的向量。 :)

ns宏是设置命名空间的一种标准且方便的方法,但我花了很长时间才正确地学习它。我发现最好的方法是复制其他人的设置代码,直到我学会如何正确地做。

顺便说一句,使用 require 而不是 :require 并不重要,尽管标准是使用 :require 所以它看起来不像是对该函数的直接调用。