Clojure 创建一个函数,该函数返回比上一个函数调用少一个长度的向量的所有切片
比如说,Clojure 创建一个函数,该函数返回比上一个函数调用少一个长度的向量的所有切片,clojure,Clojure,比如说, (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], e
(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,我自己创建这个问题是为了更好地理解闭包在闭包中是如何工作的。由于所有东西都是不可变的,我无法弄清楚如何在我要编写的闭包中存储状态。在clojure中以这种方式创建保留状态的函数是非常不习惯的,更普遍的是在函数式编程中。函数式编程通常是关于保持函数“”的,这可以简单地说是“对于相同的输入,函数将始终返回相同的值”(因此可以用其返回值替换函数调用)。您的函数显然不是引用透明的,因为它将基于调用历史而不是仅基于其输入参数(它不接受任何输入参数)返回不同的值。根据您的经验,使用不变的数据结构很难实现这一点 一种更具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))
这样,您就可以只使用不可变结构,实现引用透明,甚至支持惰性计算!赢 在clojure中以这种方式生成保留状态的函数是非常不习惯的,更普遍的是在函数式编程中。函数式编程通常是关于保持函数“”的,这可以简单地说是“对于相同的输入,函数将始终返回相同的值”(因此可以用其返回值替换函数调用)。您的函数显然不是引用透明的,因为它将基于调用历史而不是仅基于其输入参数(它不接受任何输入参数)返回不同的值。根据您的经验,使用不变的数据结构很难实现这一点 一种更具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))
这样,您就可以只使用不可变结构,实现引用透明,甚至支持惰性计算!赢 作为练习,我会选择这样的方式:
(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))
以此类推作为练习,我会选择这样的方式:
(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))
以此类推这是一个使用原子和协议+记录的可变版本,只是为了好玩:
(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
我希望可以用一种方式来包装它,即我们可以有它的多个实例(记录中的本地原子),尽管您可以返回更新的记录这里是一个使用原子和协议+记录的可变版本,只是为了好玩:
(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
我希望可以用一种方式来包装它,即我们可以有它的多个实例(记录中的本地原子),尽管您可以使用reverse和count返回更新的记录,但这不是很懒惰。真正的amalloy,reverse应该用于“范围”,而“count”只实现输入序列,而不是结果。用反向和计数更改应答,这不是很懒惰。真正的amalloy,反向应该用于“范围”,而“计数”只实现输入序列,而不是结果。改变答案