执行功能直到某些条件成立

时间:2011-03-11 21:16:50

标签: clojure functional-programming

我想重复将一些函数应用到某个状态,直到条件成立为止。

函数f采用状态,修改它并返回它。再次将f应用于返回状态,依此类推。

我认为这样可行。

(first (filter pred (iterate f x)))

但它有点难看。加上内存消耗并不理想,因为迭代器将被强制评估并保持中间状态,直到返回pred保持为true的状态为止,此时中间状态应该被垃圾收集。

我知道你可以编写一个简单的递归函数:

(loop [f x p] (if (p x) x (recur f (f x) p))

但我正在寻找一个核心库函数(或某些函数组合),它们以相同的内存效率执行相同的操作。

6 个答案:

答案 0 :(得分:5)

你真正想要的是take-while

take-while
function

Usage: (take-while pred coll)
Returns a lazy sequence of successive items from coll while
(pred item) returns true. pred must be free of side-effects.

修改

使用高阶函数来实现所需结果的方法可能是将函数包装成trampoline要使用的函数,即一个将返回最终结果的函数或另一个将执行的函数下一步。这是代码:

(defn iterable [f]            ; wraps your function
  (fn step [pred x]           ; returns a new function which will accept the predicate
    (let [y (f x)]            ; calculate the current step result
      (if (pred y)            ; recursion stop condition
        (fn [] (step pred y)) ; then: return a new fn for trampoline, operates on y
        y))))                 ; else: return a value to exit the trampoline

迭代执行如下:

(trampoline (iterable dec) pos? 10)

答案 1 :(得分:4)

不确定iterator的含义 - 您使用它就像iterate一样,我只想确定您的意思。无论如何,你的解决方案看起来很好,而且一点也不丑。内存也不是问题:iterate可以随时丢弃中间结果,因为你没有对它们进行任何引用,只是以“流”方式调用它上面的filter

答案 2 :(得分:3)

我认为你应该让你的循环成为一个简单的递归函数:

(defn do-until [f x p]
  (if (p x) x (recur f (f x) p)))

(do-until inc 0 #(> % 10)) ; => 11

答案 3 :(得分:3)

drop-while

怎么样?
(first (drop-while (comp not pred) (iterate f x))

答案 4 :(得分:2)

我认为没有一个核心功能可以完全有效地完成这项工作。因此,我会使用loop / recur执行此操作,如下所示:

(loop [x initial-value]
  (if (pred x) x (recur (f x))))

Loop / recur非常高效,因为它不需要额外的存储空间,而是作为JVM中的简单循环实现的。

如果你要做很多事情,那么你总是可以将模式封装在一个宏中。

答案 5 :(得分:0)

听起来你想要while宏。

http://richhickey.github.com/clojure/clojure.core-api.html#clojure.core/while

  

用法:(测试和身体时)   当测试表达式为真时,重复执行body。假定   一些副作用会导致测试成为假/零。返回nil

在略有不同的用例中,for宏支持:when和:while选项。

http://richhickey.github.com/clojure/clojure.core-api.html#clojure.core/for

  

用法:(对于seq-exprs body-expr)   列表理解。采用一个或多个向量   binding-form / collection-expr对,每个对后跟零或更多   修饰符,并产生一个懒惰的expr评估序列。   集合以嵌套方式迭代,最快,   和嵌套的coll-exprs可以引用先前创建的绑定   绑定形式。支持的修饰符是:: let [binding-form expr ...],   :测试时,:测试时。

     

(取100(对于[x(范围100000000)y(范围1000000):while(< y x)] [x y]))