将文件名传递给Clojure中的方法

时间:2014-08-17 13:44:23

标签: input parameters clojure args

我在args [0]上有一个文件名(例如(第一个args),我想把它从我的main方法传递给 slurp-std-input 。我试着做了以下但是我收到这个错误:

CompilerException java.lang.RuntimeException:无法在此上下文中解析符号:enc,编译:(regexdna / core.clj:19:3)

这两种方法的代码是:

(defn -main
  [& args]
  (let [content (slurp-std-input (first args))
        original-len (count content)
        ;; I'd prefer if I could use the regexp #"(^>.*)?\n" like the
        ;; Perl benchmark does, but that only matches ^ at the beginning
        ;; of the string, not at the beginning of a line in the middle
        ;; of the string.
        content (str/replace content #"(^>.*|\n>.*)?\n" "")
        dna-seq-only-len (count content)]

    (doseq [[re num-matches] (pmap #(count-regex-occurrences % content)
                                   dna-seq-regexes)]
      (spit "./scratch/output.txt" (format "%s %d\n" re num-matches):append true))

    (let [content (reduce one-replacement content iub-codes)]
      (spit "./scratch/output.txt" (format "\n%d\n%d\n%d\n" original-len dna-seq-only-len (count content)) :append true)))
  (flush))

以及我想传递(first args)参数的方法,所以我可以读取(first args)中包含的String文件名:

(defn slurp-std-input [args]
  ;; Reads the standard input using the encoding enc into a string and
  ;; returns it.
  ([] (slurp-std-input (.name (java.nio.charset.Charset/defaultCharset))))
  ([#^String enc]
     (with-open [r (new java.io.BufferedReader (clojure.java.io/reader args))]
       (let [sb (new StringBuilder)]
     (loop [c (.read r)]
       (if (neg? c)
         (str sb)
         (do
           (.append sb (char c))
           (recur (.read r)))))))))

请注意,我已将 中的读取更改为读取args [o]

中包含的文件

2 个答案:

答案 0 :(得分:1)

您的语法无效。如果您提供具有不同arities的方法的多个实现,那么正确的语法就像我在下面所说的那样。基本上,你在第一行的args是不正确的。

(defn slurp-std-input
  ;; Reads the standard input using the encoding enc into a string and
  ;; returns it.
  ([fname]
   (with-open [r (new java.io.BufferedReader (clojure.java.io/reader fname))]
     (let [sb (new StringBuilder)]
       (loop [c (.read r)]
         (if (neg? c)
           (str sb)
           (do
             (.append sb (char c))
             (recur (.read r)))))))))

编辑:改变了一下代码。您对#^ String enc?

的意图是什么?

答案 1 :(得分:0)

RedDeckWins走在正确的轨道上,但我觉得我可以更好地帮助在一个单独的答案中澄清问题,并指出其他一些事情,而我还在其中。

这至少可以解决您获得的错误:

(defn slurp-std-input ;; (1)
  "Reads the standard input using the encoding enc into a string and
   returns it." ;; (2)
  ([fname] 
    (slurp-std-input fname (.name (java.nio.charset.Charset/defaultCharset))))
  ([fname ^String enc] ;; (3)
     (with-open [r (new java.io.BufferedReader 
                     (clojure.java.io/reader fname :encoding enc))]
       (let [sb (new StringBuilder)]
         (loop [c (.read r)]
           (if (neg? c)
             (str sb)
             (do
               (.append sb (char c))
               (recur (.read r)))))))))

请注意以上三点:

  1. 这就是你的问题所在 - 你定义了一个具有多个arities的函数,但是第一行是(defn slurp-std-input [args] - 这意味着该函数具有arity 1,所以之后的任何事情都是[args]必须是fixed-arity函数的单一定义。那不是你想要的,所以摆脱[args],你应该好好去。

  2. Clojure中的约定是通过函数名后面的字符串来记录函数。这使用户可以通过(doc slurp-std-input)

  3. 获取您的功能文档
  4. 您的类型提示语法略有偏差。它应该是^String enc,而不是#^String enc


  5. 编辑:我刚刚意识到您的代码使用的是args,因为符号args没有绑定到任何内容,它将不再适用于我所做的更正。不过,我想我已经想出了你的意图。我上面编辑了我的代码。你的函数应该有可能的arities 1和2,而不是0和1.你至少要传递一个参数 - 文件名 - 你也可以选择传递一个编码。


    编辑#2:这是一个依赖于clojure.core/slurp的修订版,它可以方便地使用encoding等可选参数:

    (defn slurp-std-input
      "Returns the contents of a file as a string. 
       Optionally takes an encoding as a second argument."
      ([fname] (slurp fname))
      ([fname ^String enc] (slurp fname :encoding enc)))
    

    请注意,这实际上只是clojure.core/slurp的包装器,因此您正在啜饮来自标准输入的文件名这一事实实际上是无关紧要的。如果我要编写这样的函数,我会称它为slurp-plusslurp'之类的东西。