我编写了这个从树中获取元素的函数。它只是这个:
(defn at [address tree] (reduce nth tree address))
现在问题是nth
有2个重载;如果索引超出范围则抛出异常,并且返回not-found
参数而不是抛出异常的异常。
现在我可以为我的函数添加一个重载来添加这个选项:
(defn at [address tree not-found]
(reduce (fn [curr-tree index] (nth curr-tree index not-found))
tree address))
我可以抱怨我必须自己明确地创建一个新函数而不是漂亮的nth
。
这不是真正的问题。我不应该为nth
的每个重载做过载。
nth
只有两个重载,但在其他时候,当我想编写类似包装器的函数时,如何将决策推迟给用户。在这个例子中,我只是包裹nth
;为了保持一致,我希望at
模仿nth
的行为。如何继承其他功能的选项?
我从clojure的角度提出这个问题,但它可能适用于其他语言,也可能不适用于其他语言。
答案 0 :(得分:3)
为什么要根据at
的设计设计nth
?致电at
的人不应该考虑nth
的超载。
at
可以像@ amalloy的答案一样传递函数。但我建议从一个更简单的设计开始,然后在需要时进行重构:
(defn at
([address tree]
(reduce nth tree address))
([address tree not-found]
(reduce #(nth %1 %2 not-found) tree address)))
我的理由是传递not-found
值比传递函数更容易理解:
(def maybe-x (at addr tree :bummer))
;; See @amalloy's answer
(def maybe-x (at' addr tree #(nth %1 %2 :bummer))))
事实上,如果我稍后需要传递其他功能,我会创建一个新的at-by
函数(参见group-by)。
答案 1 :(得分:2)
也许是这样的?
(defn at [address tree & more]
(reduce (fn [a i] (apply nth a i more)) tree address))
& more
获取用户可能提供的任何额外参数,apply
将其粘贴到nth
的调用结束,而不必担心nth
{1}}将与他们有关。
但从风格上讲,我更喜欢写出重载。它将更好地记录您的功能支持哪些选项,并且更容易维护。
答案 2 :(得分:2)
你可以使用函数参数来调用而不是nth,然后你不关心它有多少重载,因为调用者将处理他们实际想要使用的一个重载。
(defn at
([address tree]
(at address tree nth))
([address tree f]
(reduce f tree address)))
(at [whatever] some-tree #(nth % %2 nil))