Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 创建一个函数,该函数返回比上一个函数调用少一个长度的向量的所有切片_Clojure - Fatal编程技术网

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,反向应该用于“范围”,而“计数”只实现输入序列,而不是结果。改变答案