例如,
(def sample-arr [10, 7, 5, 8, 11, 9])
(defn create-func [arr]
;; Code goes here)
(def result-function (create-func sample-arr))
(result-function) => [7, 5, 8, 11, 9], [10, 7, 5, 8, 11]
(result-function) => [7, 5, 8, 9], [10, 7, 5, 8], etc
(result-function) => {all subarays of length 2}
历史:我正在学习Clojure,我自己创建了这个问题,以便更好地理解Closure中闭包的工作原理。一切都是不可变的,我无法弄清楚如何将状态存储在我想写的闭包中。
答案 0 :(得分:3)
在clojure中创建以这种方式保留状态的函数是非常不恰当的,更常见的是在函数式编程中。函数式编程通常是关于保持你的函数" referentially transparent",它可以简单地作为"函数将始终为相同的输入返回相同的值" (因此可以用其返回值替换函数调用)。你的函数显然不是引用透明的,因为它将根据调用历史记录返回一个不同的值,而不是仅依赖于它的输入参数(它不需要任何参数)。在您进行实验时,使用不可变数据结构很难实现。
更具FP风格的方法是制作构建一个"懒惰"列表中列表中的每个项目都是您建议的连续呼叫的结果:
(defn all-subs [input-arr]
(map (fn[length] (partition length 1 input-arr)) (reverse (range 1 (count input-arr)))))
有了这个,你得到:
(def result (all-subs [10, 7, 5, 8, 11, 9]))
(first result)
=> ((10 7 5 8 11) (7 5 8 11 9))
(second result)
=> ((10 7 5 8) (7 5 8 11) (5 8 11 9))
(nth result 3)
=>((10 7) (7 5) (5 8) (8 11) (11 9))
这样你只能使用不可变结构,引用透明,甚至支持延迟计算!赢了!
答案 1 :(得分:0)
作为一种练习,我会选择类似的东西:
(defn all-partitions
([items] (all-partitions items (count items)))
([items n] (with-meta (partition n 1 items)
{:next #(all-partitions items (dec n))})))
对此函数的调用返回分区,此结果的元数据包含对同一集合进行分区的函数,但组中只有一个项目:
(def res (all-partitions [1 2 3 4 5 6 7]))
(println res)
;;=> ((1 2 3 4 5 6 7))
(def res2 ((-> res meta :next)))
(println res2)
;;=> ((1 2 3 4 5 6) (2 3 4 5 6 7))
(def res3 ((-> res2 meta :next)))
(println res3)
;;=> ((1 2 3 4 5) (2 3 4 5 6) (3 4 5 6 7))
等等
答案 2 :(得分:0)
这是一个可变版本,使用原子和协议+记录只是为了好玩:
(def n (atom 0))
(def init-len (atom 0))
(def final-result (atom nil))
(defprotocol StateFunction
(init [this])
(iter [this])
(reset [this]))
(defrecord ResultFunction [coll]
StateFunction
(init [this]
(let [len (count coll)]
(do (reset! n len)
(reset! init-len len)
(reset! bcoll coll))))
(iter [this]
(let [delta (inc (- @init-len @n))]
(if (nil? @final-result)
(loop [base coll
result '()
i 0]
(cond (>= i delta)
(let [_ (swap! n dec)
_ (if (zero? @n) (reset! final-result result))]
result)
:else
(recur (rest base) (conj result (take @n base)) (inc i))))
@final-result)))
(reset [this]
(do (reset! n 0) (reset! init-len 0) (reset! bcoll []) (reset! final-result nil))))
(defn create-func [coll]
(let [my-fun (map->ResultFunction {:coll coll})]
(init my-fun)
my-fun))
(def my-fun (create-func [1 2 3 4 5 6 7 8 9]))
(iter my-fun) ;; gives next list of partitions, result at n = 1 is stored to avoir redo
(reset my-fun) ;; resets atoms, you can next init them to restart the cycle
我希望有可能以一种我们可以拥有它的多个实例(记录中的局部原子)的方式包装它,尽管你可以返回更新的记录