清理 Clojure 函数
来自命令式编程语言,我正在尝试了解 Clojure,希望利用它的多线程功能。
4Clojure 的问题之一是编写一个函数,生成长度为 N 的斐波那契数列表,对于 N > 1. 我编写了一个函数,但鉴于我的背景有限,我想了解一下这是否是最好的 Clojure 处理方式。代码如下:
(fn fib [x] (cond
(= x 2) '(1 1)
:else (reverse (conj (reverse (fib (dec x))) (+ (last (fib (dec x))) (-> (fib (dec x)) reverse rest first))))
))
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
最惯用的“功能”方法可能是创建一个无限惰性的斐波那契数序列,然后提取前 n 个值,即:
以下链接有一些非常有趣的方法来沿着这些线生成斐波那契数列:
http://en.wikibooks.org/wiki/Clojure_Programming/Examples/Lazy_Fibonacci
最后,这是另一个值得考虑的有趣实现:
它并不那么简洁,但很好地演示了使用 Clojure 的解构、惰性序列和高阶函数来解决该问题。
The most idiomatic "functional" way would probably be to create an infinite lazy sequence of fibonacci numbers and then extract the first n values, i.e.:
The following link has some very interesting ways of generating fibonnaci sequences along those lines:
http://en.wikibooks.org/wiki/Clojure_Programming/Examples/Lazy_Fibonacci
Finally here is another fun implementation to consider:
It's not as concise as it could be, but demonstrates quite nicely the use of Clojure's destructuring, lazy sequences and higher order functions to solve the problem.
这是我非常喜欢的斐波那契版本(我从 clojure wikibook 中获取了实现:http:// en.wikibooks.org/wiki/Clojure_Programming)
它的工作原理如下:假设您已经拥有无限的斐波那契数列。如果您取出序列的尾部并将其按元素添加到原始序列中,您将得到斐波那契序列(尾部的尾部),
因此您可以使用它来计算序列。您需要两个初始元素 [0 1](或 [1 1],具体取决于您开始序列的位置),然后只需映射添加元素的两个序列即可。请注意,这里需要惰性序列。
我认为这是最优雅且(至少对我来说)最令人费解的实现。
编辑:fib 函数是
Here is a version of Fibonacci that I like very much (I took the implementation from the clojure wikibook: http://en.wikibooks.org/wiki/Clojure_Programming)
It works like this: Imagine you already have the infinite sequence of Fibonacci numbers. If you take the tail of the sequence and add it element-wise to the original sequence you get the (tail of the tail of the) Fibonacci sequence
thus you can use this to calculate the sequence. You need two initial elements [0 1] (or [1 1] depending on where you start the sequence) and then you just map over the two sequences adding the elements. Note that you need lazy sequences here.
I think this is the most elegant and (at least for me) mind stretching implementation.
Edit: The fib function is
这是一种可以让您接触到惰性序列的方法,尽管它肯定不是计算斐波那契序列的最佳方法。
给出斐波那契数列的定义,我们可以看到它是通过将相同的规则重复应用于
'(1 1)
的基本情况而构建的。 Clojure 函数iterate
听起来很适合这个:因此,对于我们的函数,我们需要一些东西来获取我们到目前为止计算的值,对最近的两个值求和,然后返回一个列表新值和所有旧值。
这里的参数列表仅意味着 x 和 y 将绑定到作为函数参数传递的列表中的前两个值,该列表包含前两个值之后的所有参数将绑定到
_
,并且可以通过all
引用作为参数传递给函数的原始列表。现在,迭代将返回中间值的无限序列,因此对于我们的情况,我们希望将其包装在仅返回我们感兴趣的值的内容中;惰性求值将停止整个无限序列的求值。
另请注意,这会以与您的实现相反的顺序返回结果;当然,用
reverse
解决这个问题很简单。编辑:或者实际上,正如 amalloy 所说,通过使用向量:
Here's one way of doing it that gives you a bit of exposure to lazy sequences, although it's certainly not really an optimal way of computing the Fibonacci sequence.
Given the definition of the Fibonacci sequence, we can see that it's built up by repeatedly applying the same rule to the base case of
'(1 1)
. The Clojure functioniterate
sounds like it would be good for this:So for our function we'd want something that takes the values we've computed so far, sums the two most recent, and returns a list of the new value and all the old values.
The argument list here just means that
x
andy
will be bound to the first two values from the list passed as the function's argument, a list containing all arguments after the first two will be bound to_
, and the original list passed as an argument to the function can be referred to viaall
.Now,
iterate
will return an infinite sequence of intermediate values, so for our case we'll want to wrap it in something that'll just return the value we're interested in; lazy evaluation will stop the entire infinite sequence being evaluated.Note also that this returns the result in the opposite order to your implementation; it's a simple matter to fix this with
reverse
of course.Edit: or indeed, as amalloy says, by using vectors:
请参阅 Stu Halloway 编写的Clojure 编程中的 Christophe Grand 斐波那契解决方案。这是我见过的最优雅的解决方案。
另请参阅
如何使用生成斐波那契序列Clojure?
See Christophe Grand's Fibonacci solution in Programming Clojure by Stu Halloway. It is the most elegant solution I have seen.
Also see
How can I generate the Fibonacci sequence using Clojure?