如何在Clojure中创建一个最多执行N次操作的函数?

时间:2014-10-30 16:23:40

标签: clojure

首先,我有一个像这样的Mysql表:

create table t (id int(11) PRIMARY KEY unsigned NOT NULL AUTO_INCREMENT, name varchar(20), age int(10));

我定义了一个在t:

中创建一行的函数
(require '[honeysql.core :as sql])

(defn do-something []
    (sql/query {:insert-into  :t
                :values [{:name "name1" :age 10}]})
    (> 3 (rand-int 5)))

现在我想运行这个函数,直到它返回true但最多N次。

这个take-times代码是错误的,因为repeat会一次评估do-something函数,然后构造惰性序列。

(defn take-times []
   (some true? (repeat 5 (do-something))))

无论take-times2返回什么,此do-something都会评估do-something 5次。

(defn take-times2 []
    (some true? (for [i (range 5)]
                  (do-something))))

如果我不使用递归函数和宏,我该怎么办?

2 个答案:

答案 0 :(得分:5)

这应该有效:

(->> (repeatedly do-something)
     (take 5)
     (some true?))

更新(04.11.2014):

由于repeatedly实际上允许可选的长度参数,所以这也没关系:

(some true? (repeatedly 5 do-something))

示例

(defn do-something
  []
  ;; 20% chance of true
  (let [ret (rand-nth [true false false false false])]
    (prn 'hello ret)
    ret))

(defn run
  []
  (->> (repeatedly do-something)
       (take 5)
       (some true?)))

(run)
;; hello false
;; hello false
;; hello true
;; => true

(run)
;; hello false
;; hello false
;; hello false
;; hello false
;; hello false
;; => nil

答案 1 :(得分:0)

reduce函数具有减少的选项,可以根据用户定义的标准停止处理序列。

使用真假的随机序列

(defn rand-seq [] (repeatedly #(rand-nth [true false false false false])))

使用reduce构建一个向量,直到找到一个true或者达到最大错误值数。

(defn at-most-or-true [s max-false]
  (reduce (fn [acc v]
      (if (and (not v) (< (count acc) max-false))
        (conj acc v)
        (reduced acc))) 
    [] s))

可以通过调用

来测试
 (at-most-or-true (rand-seq) 5)