savior
savior

Reputation: 832

How can I make a function that execute another function at most N times in Clojure?

First of All, I have a Mysql table like this:

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

I define a funtion that will create a row in t:

(require '[honeysql.core :as sql])

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

And now I want to run this function until it return true but at most N times.

This take-timescode is wrong because repeat will eval the do-something function one time and then structure the lazy sequence.

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

This take-times2 will eval the do-something 5 times no matter what the do-something return.

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

What should I do if i do not use recursion function and macro?

Upvotes: 3

Views: 194

Answers (2)

xsc
xsc

Reputation: 6073

This should work:

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

Update (04.11.2014):

Since repeatedly actually allows for an optional length parameter, this is also fine:

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

Example

(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

Upvotes: 5

GregA100k
GregA100k

Reputation: 1395

The reduce function has the reduced option to stop processing a sequence based on a user defined criteria.

Using the random sequence of true and false

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

Use reduce to build a vector until either a true is found or a maximum number of false values has been reached.

(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))

This can be tested by calling

 (at-most-or-true (rand-seq) 5)

Upvotes: 0

Related Questions