简体   繁体   English

带谓词的Clojure默认值

[英]Clojure default value with predicate

A common pattern is to provide a default value if some value does not fulfill a predicate. 常见的模式是,如果某些值不满足谓词,则提供默认值。 What is a good way of writing such a pattern when the value is not bound to a name? 当值绑定到名称时,写这种模式的好方法是什么?

Currently I use a let expression. 目前,我使用let表达式。 If for example I would like to provide a default value for empty strings I might write something like: 例如,如果我想为空字符串提供默认值,我可能会写类似:

(let [value {:a "foo"}]
  (if (:a value) value {:a "bar"})) 

However, I feel like this could be simplified to closer match the same proceduce for falsy values. 但是,我认为可以简化此过程以更紧密地匹配伪造值的相同过程。

(or value default)

I have considered creating a function that does it: 我考虑过创建一个可以做到的函数:

(defn or-default [pred value default]
  (if (pred value) value default))

With which the above example would become: 上面的示例将变为:

(or-default :a {:a "foo"} {:a "bar"})

However I assume someone must have thought about this earlier, so is there an established way? 但是我认为一定有人早些考虑过,所以有没有确定的方法?

You can use destructuring to solve this 您可以使用解构来解决此问题

(let [{:keys [a] :or {a "default"}} {:b "foo"}] a)
;; => default

Also, get lets you provide a default value: 另外,使用get可以提供默认值:

(get :a {:b "foo"} "default")
;; => default

Also works with keyword access 也适用于关键字访问

 (:a {:b "foo"} "default")
 ;;=> default

For supplying default values for map keys, the function you are looking for is essentially merge with the defaults as the first argument: 为了提供映射键的默认值,您要查找的函数实际上与默认值merge为第一个参数:

(merge {:a :a-default} {})
=> {:a :a-default}
(merge {:a :a-default} {:b 1})
=> {:a :a-default, :b 1}
(merge {:b 1, :a 2} {:a :a-default} {:b 1, :a 2})
=> {:b 1, :a 2}

We can package this as function map-defaults that, given the defaults, returns a function that fills them in: 我们可以将其打包为map-defaults函数,给定默认值,该函数将返回一个将其填充的函数:

(defn map-defaults [defaults]
  (partial merge defaults))

We can use this to create functions that perform particular defaults: 我们可以使用它来创建执行特定默认值的函数:

(def person-default 
  (map-defaults
    {:income 0
     :married false
     :forenames []}))

(person-default {})
=> {:income 0, :married false, :forenames []}

(person-default {:married true, :income 88000})
=> {:income 88000, :married true, :forenames []}

It is in the nature of defaults that they are used repeatedly, and the above is an easy way to do this. 默认情况下,重复使用它们是自然的,上面是实现此目的的简便方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM