Clojure和Varags打招呼

Clojure和Varags打招呼,clojure,Clojure,输入:“Michael”“Julia”“Joe”“Sam” 输出:嗨,Michael,Julia,Joe和Sam(注意逗号和单词“and”) 输入:无 输出:嗨,世界 这是我的第一次尝试: (defn say-hi [& name] (print "Hi," name)) user> (say-hi "Michael") Hi, (Michael) nil user> (say-hi "Michael" "Julia") Hi, (Michael Julia) nil

输入:“Michael”“Julia”“Joe”“Sam”

输出:嗨,Michael,Julia,Joe和Sam(注意逗号和单词“and”)

输入:无

输出:嗨,世界

这是我的第一次尝试:

(defn say-hi [& name]
  (print "Hi," name))


user> (say-hi "Michael")
Hi, (Michael)
nil
user> (say-hi "Michael" "Julia")
Hi, (Michael Julia)
nil
问题:

  • 如何实现默认值:(无输入,说“Hi World!”)

  • 如何摆脱输出中名称周围的父对象

  • 如何实现逗号分隔并添加连词“and”


  • 首先,Clojure支持多个arity函数,因此您可以这样做以实现默认行为:

    (defn say-hi
      ([] (say-hi "World"))
      ([& names] ...))
    
    然后,您要做的是获取一个seq并将它包含的所有字符串连接在一起,中间使用
    “,”
    clojure.string
    名称空间包含许多字符串操作函数,其中一个是
    clojure.string/join

    (require '[clojure.string :as string])
    (string/join ", " ["Michael", "Julia"])
    ;; => "Michael, Julia"
    
    (use '[clojure.string :only [join]])
    
    (defn sentencify [& elems]
      (->>
        [(join ", " (butlast elems)) (last elems)]
        (remove empty?)
        (join " and ")))
    
    (defn say-hi [& name]
      (print "Hi," (if name
                      (sentencify name)
                      "World!")))
    
    但是seq的最后一个元素应该使用
    和“
    作为分隔符连接起来,因此您将得到如下结果:

    (require '[clojure.string :as string])
    (defn say-hi
      ([] (say-hi "World"))
      ([& names]
       (if (next names)
         (format "Hi, %s, and %s!"
                 (string/join ", " (butlast names))
                 (last names))
         (format "Hi, %s!" (first names)))))
    
    请注意,您必须区分单个名称和多个名称的情况,并且
    (下一个名称)
    基本上检查seq是否包含多个元素。(您可以通过向函数添加另一个arity来实现这一点。)


    您可以使用
    clojure.string/join

    (require '[clojure.string :as string])
    (string/join ", " ["Michael", "Julia"])
    ;; => "Michael, Julia"
    
    (use '[clojure.string :only [join]])
    
    (defn sentencify [& elems]
      (->>
        [(join ", " (butlast elems)) (last elems)]
        (remove empty?)
        (join " and ")))
    
    (defn say-hi [& name]
      (print "Hi," (if name
                      (sentencify name)
                      "World!")))
    
    简明的解决方案:

    (defn say-hi [& names]
      (let [names (case (count names)
                    0 ["world"]
                    1 names
                    (concat (butlast names) (list (str "and " (last names)))))]
        (->> names, (cons "Hi"), (interpose ", "), (apply str))))
    
    (say-hi)
    ;"Hi, world"
    
    (say-hi "Michael")
    ;"Hi, Michael"
    
    (say-hi "Michael" "Julia" "Joe" "Sam")
    ;"Hi, Michael, Julia, Joe, and Sam"
    
    对于长的
    名称列表
    ,您可能希望避免使用
    计数
    最后一个
    、和
    但是最后一个
    ,可以先将
    名称
    倒入向量中


    要打印(如问题所示)而不是返回格式化字符串,请将
    print
    附加到最终表单:

    (->> names, (cons "Hi"), (interpose ", "), (apply str), print)
    

    我担心判刑部分不起作用:
    (打声招呼“Michael”)IllegalArgumentException不知道如何从以下位置创建ISeq:clojure.core$name clojure.lang.RT.seqFrom(RT.java:505)
    修复了打字错误<代码>判刑也应该接受varargs。非常感谢您的解释——它非常清晰易懂。多重算术函数使代码易于阅读。和
    (如果(下一个名称)…
    检查工作得很好!也许返回输出而不是打印它?谢谢!它是有效的,这个概念甚至适用于更大的问题。顺便问一下,如何配置REPL输出以分号开头?它真的很方便复制和过去。(我在使用Emacs+Cider-nrepl。)@Nick我伪造了输出布局。我在LightTable instarepl上做的。