我正在尝试编写一个在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这样做.
我有一个漫长而懒惰的序列,我想减少并懒惰地测试.一旦两个连续元素彼此不相同=
(或某些其他谓词),我想停止使用生产成本高昂的列表.是的,这听起来像是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建议他正确地进行了一些组合reduce
和every?
短路,还是我错过了一些已经存在的明显方法?
编辑:两种人发布了避免在懒惰序列上进行分块的解决方案,但是如何避免在进行分块时使用分块apply
,这似乎在四个分组中消耗?
编辑#2:正如Stuart Sierra所说,我独立发现,这实际上并不是分块.它只是正常应用,所以我会把它叫做关闭并给他答案.对于那些感兴趣的人,我在一个单独的答案中包含了一个小函数来完成问题的减少部分.
编辑:我在写这篇文章的过程中发现了我自己问题的部分答案,但我认为它很容易改进,所以无论如何我都会发布它.也许那里有更好的解决方案?
我正在寻找一种简单的方法来定义let
表单中的递归函数而不诉诸letfn
.这可能是一个不合理的请求,但我寻找这种技术的原因是因为我混合了数据和递归函数,这些函数在某种程度上相互依赖需要大量的嵌套let
和letfn
语句.
我想编写生成这样的惰性序列的递归函数(以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)
但正如我刚才所说,这导致了很多繁琐的嵌套和交替的let
和letfn
.
为了在没有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) 我注意到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的问题
这对你来说是一个双重问题,非常棒的Stacked Overflow Wizards.
如何在与Clojure交谈时将emacs/slime/swank设置为使用UTF-8,或者在命令行REPL中使用UTF-8?目前我无法向swank-clojure发送任何非罗马字符,并且使用命令行REPL会使事情变得糟糕.
在拉丁文本上做正则表达式真的很容易:
(re-seq#"[\ w] +""日语句子真的不需要空格吗?")
但是,如果我有一些日本人怎么办?我认为这会起作用,但我无法测试它:
(re-seq #"[(?u)\w]+" "??? ? ?? ? ? ???? ? ?? ?? ??? ???")
Run Code Online (Sandbox Code Playgroud)
如果我们必须使用字典来查找单词中断,或者自己找到一个只有片假名的单词,那就更难了:
(re-seq #"[?????-?]" "???????????????????????")
Run Code Online (Sandbox Code Playgroud)
谢谢!
我很困惑如何习惯性地更改通过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) 我试图以懒惰的方式解决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)