Clojure基于参数的灵活功能设计?

use*_*027 1 clojure

我的函数行为不同,具体取决于哪些关键字参数提供了值.对于这个问题,我想知道根据提供的参数类型,行为略有不同的函数.

示例函数,用于递增列表的每个元素:

(defn inc-list [& {:keys [list-str list]}]
  (let [prepared-list (if-not (nil? list) list (clojure.string/split list-str #","))]
    (map inc prepared-list)))
Run Code Online (Sandbox Code Playgroud)

做一个多方法而不是测试参数的类型是否有意义?我之前没有使用过多种方法,也不确定正确的时间使用它们.如果这是一个好主意,下面的例子是否有意义?

例:

(defn inc-coll [col] (map inc col))
(defmulti inc-list class)
(defmethod inc-list ::collection [col] (inc-col col))
(defmethod inc-list String [list-str] 
  (inc-col 
    (map #(Integer/parseInt %)
         (clojure.string/split list-str #",")))
Run Code Online (Sandbox Code Playgroud)

noi*_*ith 5

首先要做的事情是:(map 'inc x)将每个项目x作为关联集合处理,并查找由密钥索引的值'inc.

user> (map 'inc '[{inc 0} {inc 1} {inc 2}])
(0 1 2)
Run Code Online (Sandbox Code Playgroud)

你可能想inc代替

user> (map inc [0 1 2])
(1 2 3)
Run Code Online (Sandbox Code Playgroud)

接下来,我们尝试inc一个字符串,args string/split乱序,以及一些拼写错误.

如果您定义了multi to dispatch on class,那么方法应该由Class参数化,而不是关键字占位符.我更改了多功能,因此它适用于任何Clojure知道如何作为seq处理的东西.此外,作为一个bikeshedding,它最好使用type,它提供了区分Clojure代码class中不提供的输入的区别:

user> (type (with-meta  {:a 0 :b 1} {:type "foo"}))
"foo"
Run Code Online (Sandbox Code Playgroud)

把它们放在一起:

user> (defn inc-coll [col] (map inc col))
#'user/inc-coll
user> (defmulti inc-list type) 
nil
user> (defmethod inc-list String [list-str]
        (inc-coll (map #(Integer/parseInt %) (clojure.string/split list-str #","))))
#<MultiFn clojure.lang.MultiFn@6507d1de>
user> (inc-list "1,10,11")
(2 11 12)
user> (defmethod inc-list clojure.lang.Seqable [col] (inc-coll (seq col)))
#<MultiFn clojure.lang.MultiFn@6507d1de>
user> (inc-list [1 2 3])
(2 3 4)
Run Code Online (Sandbox Code Playgroud)