不在尾部位置

Tia*_*Oca 0 lisp recursion functional-programming tail-recursion clojure

我如何使用类似于recur尾部位置的东西?

看看我的代码:

(defn -main [& args]

  (println "Hi! Type a file name...")

  (defn readFile[])
    (let [fileName(read-line)]
    (let [rdr (reader fileName)]
      (if-not (.exists rdr) 
        ((println "Sorry, this file doesn't exists. Type a valid file name...")
         (recur)))
         (defn list '())
         (doseq [line (line-seq rdr)]
           (if-not (= "" line)
             (concat list '(line)))
             (list))))

(defn fileLinesList (readFile))
  ...
  ...)
Run Code Online (Sandbox Code Playgroud)

我知道我不能recur在这里使用......但我不知道如何在clojure中实现它.

我是Clojure的新手,我来自OOP环境.所以...

在这种情况下有没有办法使用递归? 什么是另类?

Pio*_*dyl 6

首先,您不应将函数定义嵌套在另一个函数中defn(-main在本例中).defn或者def始终在命名空间的顶层定义符号绑定,它们不嵌套.如果要定义一个局部范围的功能,你需要使用letfn,如

(let [my-fn (fn [a b] (+ a b))]
  (my-fn 1 2))
Run Code Online (Sandbox Code Playgroud)

在您的特定情况下,我认为将代码拆分为多个函数会更容易.这样它将更具可读性.

提示文件名是您逻辑的一部分.

(defn get-existing-filename []
  (let [filename (read-line)]
    (if (.exists (java.io.File. filename))
      filename
      (do
        (println "Sorry, this file doesn't exists. Type a valid file name...")
        (recur)))))
Run Code Online (Sandbox Code Playgroud)

然后你可以用它来读取删除空行的文件:

(with-open [input (clojure.java.io/reader (get-existing-filename))]
  (->> (line-seq input)
       (remove empty?)
       (doall)))
Run Code Online (Sandbox Code Playgroud)

对于包含以下内容的文件:

AAA

BBB
CCC

DDD
Run Code Online (Sandbox Code Playgroud)

它会回来

("AAA" "BBB" "CCC" "DDD")
Run Code Online (Sandbox Code Playgroud)

如果您真的希望它作为单个函数,以下将起作用:

(defn read-file []
  (let [filename (read-line)]
    (if (.exists (java.io.File. filename))
      (with-open [input (clojure.java.io/reader (get-existing-filename))]
        (->> (line-seq input)
             (remove empty?)
             (doall)))
      (do
        (println "Sorry, this file doesn't exists. Type a valid file name...")
        (recur)))))
Run Code Online (Sandbox Code Playgroud)

最后,可以从中调用此函数-main.

我还注意到示例代码中的另一个问题:

((println "Sorry, this file doesn't exists. Type a valid file name...")
 (recur))
Run Code Online (Sandbox Code Playgroud)

ifif-not要求他们thenelse分支的单个表达式.如果您想要多个表达式,则需要将它们嵌套在do:

(do
  (println "Sorry, this file doesn't exists. Type a valid file name...")
  (recur))
Run Code Online (Sandbox Code Playgroud)

如果您需要ifif-not不使用else分支,那么您可以使用whenwhen-not宏.然后你不需要包装多个表达式,因为when/ when-not会将它们包装在你的内部do.

(when true
  (println 1)
  (println 2))
Run Code Online (Sandbox Code Playgroud)

相当于

(if true
  (do
    (println 1)
    (println 2)))
Run Code Online (Sandbox Code Playgroud)