【发布时间】:2012-05-26 19:56:11
【问题描述】:
我已经从 4clojure.com 解决了 45 个问题,并且在尝试使用递归和累加器解决一些问题的过程中发现了一个反复出现的问题。
我将尽我所能解释我正在做的事情,以最终得到令人毛骨悚然的解决方案,希望一些 Clojurer 能够“得到”我没有得到的东西。
例如,问题 34 要求编写一个函数(不使用 range),以两个整数作为参数并创建一个范围(不使用范围)。简单地说,你做 (... 1 7) 你得到 (1 2 3 4 5 6)。
现在这个问题不是要解决这个特定的问题。
如果我想要使用递归和累加器解决这个问题怎么办?
我的思考过程是这样的:
我需要编写一个带有两个参数的函数,我以 (fn [x y] )
开头
-
我需要递归,我需要跟踪一个列表,我将使用一个累加器,所以我在第一个函数中编写了第二个函数,并带有一个额外的参数:
(fn [x y]
(((fn g [x y acc] ...) X 是的 '())
(显然我无法在 SO 上正确格式化 Clojure 代码!?)
这里我已经不确定我做的是否正确:第一个函数 必须 正好采用两个整数参数(不是我的调用),我不确定:如果我想使用累加器,我可以在不创建嵌套函数的情况下使用累加器吗?
然后我想conj,但是我做不到:
(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)
所以我最终做了一个额外的 flatten 并且它有效,但它非常丑陋。
我开始理解一些事情,在某些情况下,我什至开始以一种更流行的方式“思考”,但我在编写解决方案时遇到了问题。
例如在这里我决定:
- 使用累加器
- 通过递增 x 直到达到 y 来递归
但我最终得到了上面的怪物。
有很多种方法可以解决这个问题,但再次强调,这不是我想要的。
我所追求的是,在我决定 cons/conj、使用累加器并递归之后,我可以得到这个(不是我写的):
#(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)
我认为能够解决一些问题是一个开始,但我对我倾向于产生的丑陋解决方案有点失望......
【问题讨论】:
-
不要害怕扔掉不好的解决方案。如果您开始看到您的代码变得笨拙,请退后一步并重新考虑一下。当它感觉不对时,它可能不对。
-
@JeremyHeiler:好的,但“想法”并没有那么糟糕,“实现”/实际代码很糟糕。例如,使用累加器+递归的简短解决方案是由解决了 150 个 4clojure 问题的人编写的(其中一些问题确实不是微不足道的)。所以我的想法似乎还不错:但我(还)不能干净地实现我的想法。我认为拼图需要一些时间才能到位:-/
-
确实如此。继续练习和玩代码!
-
我对这些点赞和收藏感到有点惊讶:我可能不是唯一一个在尝试学习 Clojure(或任何 Lisp 方言)时面临同样问题的人。跨度>
标签: recursion clojure accumulator cons