【问题标题】:"Unable to resolve symbol" error“无法解析符号”错误
【发布时间】:2009-11-21 21:12:50
【问题描述】:

当我将此代码粘贴到 REPL 中时,它可以正常工作:

(use 'clojure.contrib.seq-utils)
(defn- random-letter [] (char (+ (rand-int 26) 97)))
(defn- random-digit [] (rand-int 10))
(defn- random-password
  "Returns an 8-character password consisting of letters and digits as follows: aa1aa1aa"
  []
  (let [password (interpose '((random-digit)) (repeat 3 (repeat 2 '(random-letter))))]
    (apply str (flatten (map (fn [coll] (map eval coll)) password)))))

现在,我有这个带有:gen-class :implements [my.ServiceInterface] 的代码和一个以- 为前缀的函数来实现接口。我使用 Maven/Groovy/TestNG 进行单元测试。其他几个接口/Clojure 实现一切正常,但在这种特殊情况下,我收到此错误:

java.lang.RuntimeException:
java.lang.Exception: Unable to resolve symbol: random-letter in this context (NO_SOURCE_FILE:32)

我不知道为什么。我唯一能说的是这个函数与所有其他函数的不同之处在于,这是我唯一使用引用的地方,即'((random-digit))'(random-letter)。编辑:另外,这是我使用eval 的唯一地方。

我尝试将函数定义为“非私有”(defn 而不是defn-)。我还在顶部尝试了(declare random-digit random-letter)。这些都不能解决问题。

附带说明,如果您对实现random-password 函数的更好方法有建议,我会全力以赴。但我仍然想知道为什么会出现此错误以及如何使其正常工作。

非常感谢您的帮助。 Clojure 很棒。

编辑:这是完整的代码。

(ns fred.hp2010.service.ClojurePoolerService
  (:gen-class :implements [fred.hp2010.service.PoolerService])
  (:use [clojure.contrib.seq-utils :only (flatten)]))

(def dao (fred.hp2010.persistence.Repository/getDao))

(declare find-by is-taken random-password)

(defn -addPooler [this pooler] (. dao insert "POOLER" pooler))
(defn -getPoolers [this] (. dao list "poolers"))
(defn -isEmailTaken [this email] (is-taken {"email" email}))
(defn -isUsernameTaken [this username] (is-taken {"username" username}))
(defn -login [this email password] (. dao findSingle "POOLER" {"email" email "password" password}))

(defn -changePassword [this email new-password]
  (let [updated-pooler (assoc (into {} (find-by {"email" email})) "password" new-password)]
    (. dao update "POOLER" "POOLER_ID" updated-pooler)))

(defn -resetPassword [this email]
  (let [new-password (random-password)]
    (-changePassword this email new-password)
    new-password))

(defn- find-by [params] (. dao findSingle "POOLER" params))
(defn- is-taken [params] (not (nil? (find-by params))))

(defn- random-letter [] (char (+ (rand-int 26) 97)))
(defn- random-digit [] (rand-int 10))
(defn- random-password
  "Returns an 8-character password consisting of letters and digits as follows: aa1aa1aa"
  []
  (let [password (interpose '((random-digit)) (repeat 3 (repeat 2 '(random-letter))))]
    (apply str (flatten (map (fn [coll] (map eval coll)) password)))))

【问题讨论】:

  • 我不知道 Clojure,但是在 Scheme 中使用 eval 需要一些环境,而您得到的错误是我在 Scheme 中所期望的。但是,唉,我不知道 Clojure,所以我无能为力,但也许这会让你走上正确的道路。 :)
  • 嗯,你可能是对的。这也是我唯一使用“eval”的地方。但是为什么它在 REPL 中起作用,而不是在执行单元测试时呢?
  • @leppie:那么你将如何在 Scheme 中解决这个问题? :-)
  • 我添加了另一个可能的解决方案,希望你喜欢!

标签: functional-programming lisp clojure


【解决方案1】:

我不知道为什么您在使用 :gen-class 编译此文件时遇到问题,但如果 eval 与此有关,我不会感到惊讶。 eval 通常是个坏主意。要尝试的一件事(完全未经测试)是使用`(反引号)而不是'(引号),以便您的符号是命名空间限定的。不知道有没有用。

也许最好摆脱eval。如果你通过repeatedly 将你的随机字符函数变成无限惰性序列,你可以这样做:

(defn- random-letter [] (repeatedly #(char (+ (rand-int 26) 97))))
(defn- random-digit  [] (repeatedly #(rand-int 10)))
(defn- random-password
  "Returns an 8-character password consisting of letters and digits as follows: aa1aa1aa"
  []
  (apply str
         (mapcat (fn [[n f]] (take n (f)))
                 [[2 random-letter]
                  [1 random-digit]
                  [2 random-letter]
                  [1 random-digit]
                  [2 random-letter]])))

【讨论】:

  • 谢谢,在使用 defn 公开函数后,` 确实解决了问题。 Brian,您对 Clojure 有什么<i>不</i>了解的吗? ;-) 不过,您关于 eval 是一个坏主意的观点是正确的。我试图找出一个更优雅的解决方案。我确实喜欢有 3 对字母并在其中插入数字的想法,而不是 2-1-2-1-2 解决方案。
  • "repeatedly" 是我所缺少的。这个怎么样? (apply str (take 8 (flatten (repeatedly #(list (random-letter) (random-letter) (random-digit))))))
  • 是的,这是另一个好方法。它让我想起了cycle,我会进行编辑。除非您要生成十亿个密码并且需要它的速度,否则任何可行的方法都可能很好。
【解决方案2】:

在前几行中,我在遵循语法时遇到了一些麻烦。特别是,为什么第 7 行中的所有引号?所有这些表达式的延迟评估可能对您没有帮助。我猜引用的'(random-letter) 会破坏你的乐趣。

您可以编写更简单的代码,同时避开eval。我打算在 REPL 中尝试一下,我希望很快就会有一个改进的版本。

编辑:

好的,这行得通:

(apply str (interpose (random-digit) (repeat 3 (apply str (repeat 2 (random-letter))))))

...它不需要来自clojure.contrib 的任何东西 :)

str 函数会将任何参数组合成一个字符串。如果参数在列表中,则使用 applystr 偷运到列表中。

正如你所说,Clojure 很酷!

编辑:

这是一个根据字符串规范生成由字母和数字组成的随机字符串的函数:

(apply str (map (fn [c] (if (= c \a) (random-letter) (random-digit))) "aanaanaa")))

它与您的规范略有不同,但我认为它很酷。

【讨论】:

  • 谢谢,但您的函数使用相同的字母和相同的数字,就像在 gg4gg4gg 中一样。我知道我的评论说 aa1aa1aa,但那是为了显示字母和数字的位置。我仍然希望它们与众不同:) 就像 xy5ma8fr 一样。
  • 啊,我想知道这是不是故意的! :) 但我想我也有解决办法。 BRB。
  • 这个怎么样? (apply str (take 8 (flatten (repeatedly #(list (random-letter) (random-letter) (random-digit))))))
  • 好吧,看起来我们最好的建议正在合并。
猜你喜欢
  • 1970-01-01
  • 2023-03-24
  • 2019-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-25
  • 2023-03-03
  • 2011-10-22
相关资源
最近更新 更多