小编iva*_*var的帖子

如何在Clojure中生成memoized递归函数?

我正在尝试编写一个在Clojure中返回memoized递归函数的函数,但是我在使递归函数看到它自己的memoized绑定时遇到了麻烦.这是因为没有创建var吗?另外,为什么我不能在用let创建的本地绑定上使用memoize?

这个稍微不同寻常的Fibonacci序列制作者从一个特定的数字开始就是我希望我能做的一个例子:

(defn make-fibo [y]
  (memoize (fn fib [x] (if (< x 2)
             y
             (+ (fib (- x 1))
                (fib (- x 2)))))))

(let [f (make-fibo 1)]
  (f 35)) ;; SLOW, not actually memoized
Run Code Online (Sandbox Code Playgroud)

使用with-local-vars似乎是正确的方法,但它对我也不起作用.我想我不能关闭vars?

(defn make-fibo [y]
  (with-local-vars [fib (fn [x] (if (< x 2)
                                  y
                                  (+ (@fib (- x 1))
                                     (@fib (- x 2)))))]
    (memoize fib)))

(let [f (make-fibo 1)]
  (f 35)) ;; Var null/null is unbound!?! 
Run Code Online (Sandbox Code Playgroud)

我当然可以手动编写一个宏来创建一个封闭的原子并自己管理memoization,但我希望没有这样的hackery这样做.

recursion closures scope clojure memoization

37
推荐指数
3
解决办法
4074
查看次数

如何避免Clojure对于我想要短路的懒惰seqs的分块行为?

我有一个漫长而懒惰的序列,我想减少并懒惰地测试.一旦两个连续元素彼此不相同=(或某些其他谓词),我想停止使用生产成本高昂的列表.是的,这听起来像是take-while,但请进一步阅读.

我想写一些简单而优雅的东西(假装一分钟every?就像这样reduce):

(every? = (range 100000000))
Run Code Online (Sandbox Code Playgroud)

但这不是懒惰的工作,所以它挂在无限的seqs.我发现这几乎和我想要的一样:

(apply = (range 100000000))
Run Code Online (Sandbox Code Playgroud)

但是,我注意到序列分块导致创建和测试额外的,不必要的元素.至少,这就是我认为这是在下面的代码中发生的事情:

;; Displays chunking behavior in groups of four on my system and prints 1 2 3 4
(apply = (map #(do (println %) %) (iterate inc 1)))

;; This prints 0 to 31
(apply = (map #(do (println %) %) (range)))
Run Code Online (Sandbox Code Playgroud)

我找到了一种解决方法take-while,并count检查所采用的元素数量,但这很麻烦.

我应该礼貌地向Rich Hickey建议他正确地进行了一些组合reduceevery?短路,还是我错过了一些已经存在的明显方法?

编辑:两种人发布了避免在懒惰序列上进行分块的解决方案,但是如何避免在进行分块时使用分块apply,这似乎在四个分组中消耗?

编辑#2:正如Stuart Sierra所说,我独立发现,这实际上并不是分块.它只是正常应用,所以我会把它叫做关闭并给他答案.对于那些感兴趣的人,我在一个单独的答案中包含了一个小函数来完成问题的减少部分.

clojure chunking lazy-sequences

14
推荐指数
1
解决办法
2678
查看次数

如何在Clojure中创建一个lazy-seq生成,匿名递归函数?

编辑:我在写这篇文章的过程中发现了我自己问题的部分答案,但我认为它很容易改进,所以无论如何我都会发布它.也许那里有更好的解决方案?

我正在寻找一种简单的方法来定义let表单中的递归函数而不诉诸letfn.这可能是一个不合理的请求,但我寻找这种技术的原因是因为我混合了数据和递归函数,这些函数在某种程度上相互依赖需要大量的嵌套letletfn语句.

我想编写生成这样的惰性序列的递归函数(以Fibonacci序列为例):

(let [fibs (lazy-cat [0 1] (map + fibs (rest fibs)))]
  (take 10 fibs))
Run Code Online (Sandbox Code Playgroud)

但似乎在clojure中,fibs在绑定期间不能使用它自己的符号.显而易见的是使用它letfn

(letfn [(fibo [] (lazy-cat [0 1] (map + (fibo) (rest (fibo)))))]
  (take 10 (fibo)))
Run Code Online (Sandbox Code Playgroud)

但正如我刚才所说,这导致了很多繁琐的嵌套和交替的letletfn.

为了在没有letfn和使用的情况下做到这一点let,我开始编写一些使用我认为的U-combinator的东西(刚刚听说过这个概念):

(let [fibs (fn [fi] (lazy-cat [0 1] (map + (fi fi) (rest (fi fi)))))]
  (take 10 (fibs fibs)))
Run Code Online (Sandbox Code Playgroud)

但如何摆脱冗余(fi fi)呢?

正是在这一点上,经过一个小时的挣扎并逐渐向组合子Q添加位,我发现了自己问题的答案.

(let [Q (fn [r] …
Run Code Online (Sandbox Code Playgroud)

recursion binding clojure combinators lazy-sequences

13
推荐指数
2
解决办法
1346
查看次数

作为向量的Clojure Lazy序列

我注意到Clojure中的延迟序列似乎在内部表示为链表(或者至少它们被视为仅具有对元素的顺序访问的序列).即使在被缓存到内存中之后,lazy-seq上的访问时间nth也是O(n),而不是像向量那样的常量时间.

;; ...created my-lazy-seq here and used the first 50,000 items

(time (nth my-lazy-seq 10000))
"Elapsed time: 1.081325 msecs"

(time (nth my-lazy-seq 20000))
"Elapsed time: 2.554563 msecs"
Run Code Online (Sandbox Code Playgroud)

如何在Clojure中以增量方式获取常量查找或创建延迟向量?

想象一下,在生成惰性向量期间,每个元素都是之前所有元素的函数,因此遍历列表所花费的时间成为一个重要因素.

相关问题只发现了这个不完整的Java片段: 设计一个懒惰的向量:const的问题

list vector clojure lazy-sequences

12
推荐指数
1
解决办法
1871
查看次数

如何在Clojure正则表达式中使用unicode(UTF-8)字符?

这对你来说是一个双重问题,非常棒的Stacked Overflow Wizards.

  1. 如何在与Clojure交谈时将emacs/slime/swank设置为使用UTF-8,或者在命令行REPL中使用UTF-8?目前我无法向swank-clojure发送任何非罗马字符,并且使用命令行REPL会使事情变得糟糕.

  2. 在拉丁文本上做正则表达式真的很容易:

    (re-seq#"[\ w] +""日语句子真的不需要空格吗?")

但是,如果我有一些日本人怎么办?我认为这会起作用,但我无法测试它:

(re-seq #"[(?u)\w]+" "??? ? ?? ? ? ???? ? ?? ?? ??? ???")
Run Code Online (Sandbox Code Playgroud)

如果我们必须使用字典来查找单词中断,或者自己找到一个只有片假名的单词,那就更难了:

(re-seq #"[?????-?]" "???????????????????????")
Run Code Online (Sandbox Code Playgroud)

谢谢!

unicode emacs clojure slime utf-8

12
推荐指数
2
解决办法
5544
查看次数

在Clojure中插入到XML文件的Zipper树中

我很困惑如何习惯性地更改通过clojure.contrib的zip-filter.xml访问的xml树.应该尝试这样做,还是有更好的方法?

假设我有一些虚拟xml文件"itemdb.xml",如下所示:

<itemlist> 
  <item id="1">
    <name>John</name>
    <desc>Works near here.</desc>
  </item>
  <item id="2">
    <name>Sally</name>
    <desc>Owner of pet store.</desc>
  </item>
</itemlist>
Run Code Online (Sandbox Code Playgroud)

我有一些代码:

(require '[clojure.zip :as zip]
  '[clojure.contrib.duck-streams :as ds]
  '[clojure.contrib.lazy-xml :as lxml]
  '[clojure.contrib.zip-filter.xml :as zf]) 

(def db (ref (zip/xml-zip (lxml/parse-trim (java.io.File. "itemdb.xml")))))

;; Test that we can traverse and parse.
(doall (map #(print (format "%10s: %s\n"
       (apply str (zf/xml-> % :name zf/text))
       (apply str (zf/xml-> % :desc zf/text))))
     (zf/xml-> @db :item)))

;; I assume something like this is needed to make the …
Run Code Online (Sandbox Code Playgroud)

xml clojure clojure-contrib

9
推荐指数
2
解决办法
1709
查看次数

项目欧拉问题"未来"的懒惰序列14

我试图以懒惰的方式解决Project Euler Problem 14.不幸的是,我可能正在尝试做不可能的事情:创建一个既懒惰的懒惰序列,又以某种方式"向前看"尚未计算的值.

我写的测试正确性的非懒惰版本是:

(defn chain-length [num]
  (loop [len 1
         n  num]
(cond
  (= n 1) len 
  (odd? n) (recur (inc len) (+ 1 (* 3 n)))
  true     (recur (inc len) (/ n 2)))))
Run Code Online (Sandbox Code Playgroud)

哪个有效,但确实很慢.当然我可以记住:

(def memoized-chain
   (memoize
     (fn [n]
       (cond
        (= n 1) 1 
         (odd? n) (+ 1 (memoized-chain (+ 1 (* 3 n))))
         true     (+ 1 (memoized-chain (/ n 2)))))))
Run Code Online (Sandbox Code Playgroud)

然而,我真正想要做的是抓住我的痒,以理解延迟序列的限制,并编写如下函数:

(def lazy-chain
     (letfn [(chain [n] (lazy-seq
                         (cons (if (odd? n)
                                 (+ 1 (nth lazy-chain …
Run Code Online (Sandbox Code Playgroud)

clojure lazy-evaluation collatz lazy-sequences

7
推荐指数
2
解决办法
589
查看次数