- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我已经解决了 4clojure.com 上的 45 个问题,并且在尝试使用递归和累加器解决一些问题的方式中,我注意到一个反复出现的问题。
我会尽我所能解释我正在做的事情,以最终得到模糊的解决方案,希望一些 Clojurers 能够“得到”我没有得到的东西。
例如,问题 34 要求编写一个函数(不使用范围),将两个整数作为参数并创建一个范围(不使用范围)。简单地说,你做 (... 1 7) 并且你得到 (1 2 3 4 5 6)。
现在这个问题不是关于解决这个特定问题。
如果我想使用递归和累加器来解决这个问题怎么办?
我的思考过程是这样的:
(conj 0 1)
(fn
[x y]
((fn g [x y acc] (if (= x y) y (conj (conj acc (g (inc x) y acc)) x)))
x
y
'()))
(1 (2 (3 4)))
(1 2 3 4)
#(loop [i %1
acc nil]
(if (<= %2 i)
(reverse acc)
(recur (inc i) (cons i acc))))
((fn
f
[x y]
(flatten
((fn
g
[x y acc]
(if (= x y) acc (conj (conj acc (g (inc x) y acc)) x)))
x
y
'())))
1
4)
最佳答案
我认为这里有几件事要学习。
第一 ,一种一般规则 - 递归函数通常具有自然顺序,而添加累加器则相反。你可以看到,因为当一个“正常”(没有累加器)递归函数运行时,它会做一些工作来计算一个值,然后递归生成列表的尾部,最后以一个空列表结束。相比之下,对于累加器,您从空列表开始并将内容添加到前面 - 它在另一个方向上增长。
所以通常,当你添加一个累加器时,你会得到一个相反的顺序。
现在通常这无关紧要。例如,如果您生成的不是序列而是一个值,该值是可交换运算符(如加法或乘法)的重复应用。那么无论哪种方式,您都会得到相同的答案。
但在你的情况下,这很重要。你将把列表倒过来:
(defn my-range-0 [lo hi] ; normal recursive solution
(if (= lo hi)
nil
(cons lo (my-range-0 (inc lo) hi))))
(deftest test-my-range-1
(is (= '(0 1 2) (my-range-0 0 3))))
(defn my-range-1 ; with an accumulator
([lo hi] (my-range-1 lo hi nil))
([lo hi acc]
(if (= lo hi)
acc
(recur (inc lo) hi (cons lo acc)))))
(deftest test-my-range-1
(is (= '(2 1 0) (my-range-1 0 3)))) ; oops! backwards!
(defn my-range-2
([lo hi] (my-range-2 lo hi nil))
([lo hi acc]
(if (= lo hi)
acc
(let [hi (dec hi)]
(recur lo hi (cons hi acc))))))
(deftest test-my-range-2
(is (= '(0 1 2) (my-range-2 0 3)))) ; back to the original order
my-range-1
中看到的那样和
my-range-2
, 编写带有累加器的函数的一种好方法是编写一个带有两组不同参数的函数。这为您提供了一个非常干净(恕我直言)的实现,而无需嵌套函数。
conj
之类的。这里 clojure 有点凌乱,但也很有用。上面我一直在用基于缺点的列表给出一个非常传统的观点。但是 clojure 鼓励您使用其他序列。与缺点列表不同,向量向右增长,而不是向左增长。所以另一种扭转结果的方法是使用向量:
(defn my-range-3 ; this looks like my-range-1
([lo hi] (my-range-3 lo hi []))
([lo hi acc]
(if (= lo hi)
acc
(recur (inc lo) hi (conj acc lo)))))
(deftest test-my-range-3 ; except that it works right!
(is (= [0 1 2] (my-range-3 0 3))))
conj
正在添加到右侧。我没有使用
conj
在
my-range-1
,所以这里重写为更清楚:
(defn my-range-4 ; my-range-1 written using conj instead of cons
([lo hi] (my-range-4 lo hi nil))
([lo hi acc]
(if (= lo hi)
acc
(recur (inc lo) hi (conj acc lo)))))
(deftest test-my-range-4
(is (= '(2 1 0) (my-range-4 0 3))))
my-range-3
非常相似。但结果是倒退的,因为我们从一个空列表开始,而不是一个空向量。在这两种情况下,
conj
在“自然”位置添加新元素。对于右侧的向量,但对于列表,它在左侧。
cons
创建一个包含两个东西(它的参数)的盒子。第一个是内容,第二个是列表的其余部分。所以名单
(1 2 3)
基本上是
(cons 1 (cons 2 (cons 3 nil)))
.相比之下,向量
[1 2 3]
更像是一个数组(虽然我认为它是使用树实现的)。
conj
有点令人困惑,因为它的工作方式取决于第一个参数。对于列表,它调用
cons
所以在左边添加东西。但是对于向量,它将数组(类似事物)扩展到右侧。另外,请注意
conj
将现有序列作为第一个参数,将要添加的内容作为第二个参数,而
cons
是相反的(首先添加的东西)。
=
将比较列表和向量并在内容相同时返回 true,但使其明确显示更清楚地显示您在每种情况下实际获得的内容。请注意
'(0 1 2)
与
'
前面就像
(list 0 1 2)
-
'
停止评估列表(没有它,
0
将被视为命令)。
关于recursion - 累加器、conj 和递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10666228/
这个问题已经有答案了: What's the difference between a method and a function? (42 个回答) 已关闭 7 年前。 我知道conj(x)和x.c
我正在尝试自学 clojure。这应该只是一个简单的函数,它接受一个值并将其前面的每个值相加并返回这些值的总和。 问题是,在 loop 函数中,numbers 没有像我期望的那样用 conj 修改 -
我正在尝试自学 clojure。这应该只是一个简单的函数,它接受一个值并将其前面的每个值相加并返回这些值的总和。 问题是,在 loop 函数中,numbers 没有像我期望的那样用 conj 修改 -
我正在尝试一些 Clojure,但现在对“conj”的行为感到困惑。请参阅以下示例: user=> (conj [1 2 3] 4) [1 2 3 4] 以上是预期的。但是现在,如果我执行以下操作:
(conj (drop-last "abcde") (last "abcde")) 返回(\e \a \b \c \d) 我很困惑。在conj的文档中,我注意到 The 'addition' may
我已经解决了 4clojure.com 上的 45 个问题,并且在尝试使用递归和累加器解决一些问题的方式中,我注意到一个反复出现的问题。 我会尽我所能解释我正在做的事情,以最终得到模糊的解决方案,希望
TL; DR 假设我有一个带有模板参数T的函数,该函数以std::vector&作为输入(请参见下文),如果T是复杂类型,我想对这个 vector 进行共轭。我怎样才能做到这一点 ? 我尝试了什么在h
我是 clojure 的新手,最初我正在经历 Clojure.org和 cheatbook . 我想知道 conj 不同行为的确切原因是什么在列表和向量上。 (conj [1 2 3] 4) [1 2
((fn foo [x] (when (> x 0) (conj (foo (dec x)) x))) 5) 对于这段代码,结果是 [5 4 3 2 1]为什么不是 [1,2,3,4,5]?我看到我们
core.typed 中的以下代码片段 (defn conj-num [coll x] (conj coll (byte x))) (t/cf (t/ann conj-num (t/IFn [(t
为什么 cons 在这种情况下与lazy-seq 一起工作,而 conj 却不行? 这有效: (defn compound-interest [p i] (cons p (lazy-seq (c
在conj中,原始集合是第一个参数,在cons中,它是第二个参数。 我是 clojure 新手,这看起来有点令人困惑。这两个函数有相似的行为,但是为什么参数顺序不同,是故意这样设计的吗? (conj
为什么这一直问 jack 是否想要一杯茶而不是其他父亲。 (defn tea-anyone "Ask 'fathers' if they would like some tea" [fathe
我知道 cons 返回一个 seq,conj 返回一个集合。我还知道 conj 将项目“添加”到集合的最佳末尾,而 cons 总是将项目“添加”到前面。这个例子说明了这两点: user=> (conj
假设我写了一个函数: (defn foo [to x] (conj to x)) 并希望通过声明 to 必须实现某些协议(protocol)来记录它(如在结构/类型中 to 必须支持调用 conj)。
我想要一个原子中的映射,可以将时间作为 Unix 时间戳进行跟踪。 所以,在我的主要功能中,我有: (defn -main [& args] (println "Server is starting"
如果我执行这段代码: vector > idft( vector > * v) { for_each(v->begin(), v->end(), conj); 然后编译器给我以下错误: dft
我不知道如何解决 GCC 中的这个链接问题。 我在 Windows 8、GCC+MingWG 4.8.1 下运行 CodeBlocks 13.12。 我创建了一个包含两个文件的项目: 主.c #inc
cons 目前的行为如下: (cons '(1 2) '(3)) ;=> ((1 2) 3) 我想实现: (magic-cons '(1 2) '(3)) ;=> (1 2 3) 我找不到这方面的资源
对我来说,std::conj(double d)仅返回d类型的double会更自然,因为结果肯定是真实的。 最佳答案 因为conj是对复数的运算。它匹配从double到std::complex的隐式转
我是一名优秀的程序员,十分优秀!