在跷跷板中返回Clojure操作时出错

在跷跷板中返回Clojure操作时出错,clojure,action,seesaw,Clojure,Action,Seesaw,此程序打开一个文件并将其读入列表 然后要求用户从列表中一次输入一个单词 但在它说话之后我就犯了一个错误 (ns EKS.Core) (use '[speech-synthesis.say :as say]) (use '[clojure.java.shell :only [sh]]) (use 'seesaw.core) (use 'seesaw.dev) (use 'seesaw.chooser) (use 'clojure.java.io) (import 'java.io.File) (n

此程序打开一个文件并将其读入列表 然后要求用户从列表中一次输入一个单词 但在它说话之后我就犯了一个错误

(ns EKS.Core)
(use '[speech-synthesis.say :as say])
(use '[clojure.java.shell :only [sh]])
(use 'seesaw.core)
(use 'seesaw.dev)
(use 'seesaw.chooser)
(use 'clojure.java.io)
(import 'java.io.File)
(native!)
(defn festival [x](sh "sh" "-c" (str "echo " x " | festival --tts")))
(defn espeak [x] (sh "espeak" x))
(defn mac-say[x] (sh "say" x))
(defn check-if-installed[x] (:exit(sh "sh" "-c" (str "command -v " x " >/dev/null 2>&1 || { echo >&2 \"\"; exit 1; }"))))


(defn env
  "Returns the system property for user.<key>"
  [key]
  (System/getProperty (str "user." key)))

(defn get-lines [fname]
  (with-open [r (reader fname)]
    (doall (line-seq r))))

(defn engine-check[]
(def engines (conj["Google" ]
(if (= (check-if-installed "festival") 0)  "Festival" )
(if (= (check-if-installed "espeak") 0) "ESpeak"   )
(if (= (check-if-installed "say") 0)  "Say"  )))(remove nil? engines))
(engine-check)

(def ListDir  (str (env "home") ))
(def speak say)

(defn setup-list[ file](
 (def ListEntry (remove #{""}  (get-lines (.getAbsolutePath file))))
 (speak (str "Enter the word " (first ListEntry)))
 (.getAbsolutePath file)
 (def current 0)))


(def Open-Action (action :handler (fn [e] (choose-file :type :open :selection-mode :files-only :dir ListDir :success-fn (fn [fc file](setup-list file))))
:name "Open"
:key "menu O"
:tip "Open  list"))


(def entry-text(text :id :entry :text "" ))

(defn check-word[] ((if (= (text entry-text) (nth ListEntry current))(speak "correct")(speak "incorrect"))(def current (+ current 1))(speak (str "Enter the word " (nth ListEntry current)))))

(def Main-Panel(grid-panel :vgap 7 :hgap 20 :border "Main" :items[ (top-bottom-split  entry-text
        (left-right-split (grid-panel :vgap 7 :items[(label :text "Correct: 0") (label :text "Incorrect: 0")]) (grid-panel :vgap 7 :items[(button :text "Next"
            :mnemonic \N
            :listen [:action (fn [e] (check-word))]) 
           (button :text "Repeat!"
            :mnemonic \\
            :listen [:action (fn[e] (speak(nth ListEntry current)))])
                                           ])   :divider-location 1/3 )
          :divider-location 1/3 )]))

(def Main-Window(frame :title "??????", :on-close :exit, :size[425 :by 172]:menubar(menubar :items[(menu :text "File" :items [Open-Action ])]) :content Main-Panel ))

(show! Main-Window)
这是我正在使用的测试文件

this
here
word

我认为导致回溯的原因是:

(defn setup-list[ file](
  (def ListEntry (remove #{""}  (get-lines (.getAbsolutePath file))))
  (speak (str "Enter the word " (first ListEntry)))
  (.getAbsolutePath file)
  (def current 0)))
注意
[file]
后面的paren。您正在调用def(这可能不是您想要做的),但是该def的结果是一个延迟序列(因为
remove
),并且由于该参数而被作为函数调用。不幸的是,现在还不清楚你想用
设置列表做什么,否则我会为你写一些更地道的东西

还有一些其他的事情你应该考虑。首先,不要在一个非常糟糕的函数中使用
(def…
。在这种情况下,我认为您真正想要的是
(让…

如果您能对代码保持多一点结构,它还将帮助您了解发生了什么。我认为格式是让类似paren的东西隐藏起来,如果你有更好的样式,它可能会更明显:

(defn setup-list [file]
  ((def ListEntry ...)
    ...))
在这里,更清楚的是def将用作函数调用,这可能不是您想要的


顺便说一句,Clojure有一些。他们有一些好东西在里面。这是一个很好的代码库示例,正如跷跷板所示。

我试图用它做的只是从文件中设置一个列表,从中说出第一个单词,并将一个变量作为计数器,然后下一个函数check word检查文本条目是否等于当前单词,并说正确或不正确,然后将计数器增加到下一个单词并说出下一个单词
(defn setup-list [file]
  (let [entries (get-lines (.getAbsolutePath file))]
    ...))
(defn setup-list [file]
  ((def ListEntry ...)
    ...))