clojure - Iteratively apply function to its result without generating a seq -


this 1 of "is there built-in/better/idiomatic/clever way this?" questions.

i want function--call fn-pow--that apply function f result of applying f argument, apply result of applying result, etc., n times. example,

(fn-pow inc 0 3) 

would equivalent to

(inc (inc (inc 0))) 

it's easy iterate:

(defn fn-pow-0   [f x n]   (nth (iterate f x) n)) 

but creates , throws away unnecessary lazy sequence.

it's not hard write function scratch. here 1 version:

(defn fn-pow-1   [f x n]   (if (> n 0)      (recur f (f x) (dec n))     x)) 

i found twice fast fn-pow-0, using criterium on (fn-pow inc 0 10000000).

i don't consider definition of fn-pow-1 unidiomatic, fn-pow seems might standard built-in function, or there may simple way define couple of higher-order functions in clever arrangement. haven't succeeded in discovering either. missing something?

the built-in looking dotimes. i'll tell why in round-about fashion.

time

what testing in benchmark overhead of level of indirection. (nth (iterate ...) n) only twice slow compiles loop when body fast function rather surprising/encouraging. if f more costly function, importance of overhead diminishes. (of course if f low-level , fast, should use low-level loop construct.)

say function takes ~ 1 ms instead

(defn my-inc [x] (thread/sleep 1) (inc x)) 

then both of these take 1 second -- difference around 2% rather 100%.

(bench (fn-pow-0 my-inc 0 1000)) (bench (fn-pow-1 my-inc 0 1000)) 

space

the other concern iterate creating unnecessary sequence. but, if not holding onto head, doing nth, aren't really creating sequence per se sequentially creating, using, , discarding lazyseq objects. in other words, using constant amount of space, though generating garbage in proportion n. however, unless f primitive or mutating argument, already producing garbage in proportion n in producing own intermediate results.

reducing garbage

an interesting compromise between fn-pow-0 , fn-pow-1

(defn fn-pow-2 [f x n] (reduce (fn [x _] (f x)) x (range n))) 

since range objects know how intelligently reduce themselves, not create additional garbage in proportion n. boils down loop well. reduce method of range:

public object reduce(ifn f, object start) {     object ret = f.invoke(start,n);     for(int x = n+1;x < end;x++)             ret = f.invoke(ret, x);     return ret; } 

this fastest of 3 (before adding primitive type-hints on n in recur version, is) slowed down my-inc.

mutation

if iterating function potentially expensive in time or space, such matrix operations, may wanting use (in contained manner) f mutates argument eliminate garbage overhead. since mutation side effect, , want side effect n times, dotimes natural choice.

for sake of example, i'll use atom stand-in, imagine bashing on mutable matrix instead.

(def my-x (atom 0))  (defn my-inc! [x] (thread/sleep 1) (swap! x inc))  (defn fn-pow-3! [f! x n] (dotimes [i n] (f! x))) 

Comments

Popular posts from this blog

c++ - How to add Crypto++ library to Qt project -

jQuery Mobile app not scrolling in Firefox -

How to use vim as editor in Matlab GUI -