清理 Clojure 函数

发布于 2024-12-04 01:26:06 字数 423 浏览 2 评论 0 原文

来自命令式编程语言,我正在尝试了解 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))))
          ))

Coming from imperative programming languages, I am trying to wrap my head around Clojure in hopes of using it for its multi-threading capability.
One of the problems from 4Clojure is to write a function that generates a list of Fibonacci numbers of length N, for N > 1. I wrote a function, but given my limited background, I would like some input on whether or not this is the best Clojure way of doing things. The code is as follows:

(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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

一笔一画续写前缘 2024-12-11 01:26:06

最惯用的“功能”方法可能是创建一个无限惰性的斐波那契数序列,然后提取前 n 个值,即:

(take n some-infinite-fibonacci-sequence)

以下链接有一些非常有趣的方法来沿着这些线生成斐波那契数列:

http://en.wikibooks.org/wiki/Clojure_Programming/Examples/Lazy_Fibonacci

最后,这是另一个值得考虑的有趣实现:

 (defn fib [n]
   (let [next-fib-pair (fn [[a b]] [b (+ a b)])
         fib-pairs (iterate next-fib-pair [1 1])
         all-fibs (map first fib-pairs)]
     (take n all-fibs)))


 (fib 6)
 => (1 1 2 3 5 8)

它并不那么简洁,但很好地演示了使用 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.:

(take n some-infinite-fibonacci-sequence)

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:

 (defn fib [n]
   (let [next-fib-pair (fn [[a b]] [b (+ a b)])
         fib-pairs (iterate next-fib-pair [1 1])
         all-fibs (map first fib-pairs)]
     (take n all-fibs)))


 (fib 6)
 => (1 1 2 3 5 8)

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.

行雁书 2024-12-11 01:26:06

这是我非常喜欢的斐波那契版本(我从 clojure wikibook 中获取了实现:http:// en.wikibooks.org/wiki/Clojure_Programming

 (def fib-seq (lazy-cat [0 1] (map + (rest fib-seq) fib-seq)))

它的工作原理如下:假设您已经拥有无限的斐波那契数列。如果您取出序列的尾部并将其按元素添加到原始序列中,您将得到斐波那契序列(尾部的尾部),

0 1 1 2 3 5 8 ...
1 1 2 3 5 8 ...
-----------------
1 2 3 5 8 13 ... 

因此您可以使用它来计算序列。您需要两个初始元素 [0 1](或 [1 1],具体取决于您开始序列的位置),然后只需映射添加元素的两个序列即可。请注意,这里需要惰性序列。

我认为这是最优雅且(至少对我来说)最令人费解的实现。

编辑:fib 函数是

 (defn fib [n] (nth fib-seq n)) 

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)

 (def fib-seq (lazy-cat [0 1] (map + (rest fib-seq) fib-seq)))

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

0 1 1 2 3 5 8 ...
1 1 2 3 5 8 ...
-----------------
1 2 3 5 8 13 ... 

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

 (defn fib [n] (nth fib-seq n)) 
禾厶谷欠 2024-12-11 01:26:06

这是一种可以让您接触到惰性序列的方法,尽管它肯定不是计算斐波那契序列的最佳方法。

给出斐波那契数列的定义,我们可以看到它是通过将相同的规则重复应用于 '(1 1) 的基本情况而构建的。 Clojure 函数 iterate 听起来很适合这个:

user> (doc iterate)
-------------------------
clojure.core/iterate
([f x])
  Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects

因此,对于我们的函数,我们需要一些东西来获取我们到目前为止计算的值,对最近的两个值求和,然后返回一个列表新值和所有旧值。

(fn [[x y & _ :as all]] (cons (+ x y) all))

这里的参数列表仅意味着 x 和 y 将绑定到作为函数参数传递的列表中的前两个值,该列表包含前两个值之后的所有参数将绑定到 _,并且可以通过 all 引用作为参数传递给函数的原始列表。

现在,迭代将返回中间值的无限序列,因此对于我们的情况,我们希望将其包装在仅返回我们感兴趣的值的内容中;惰性求值将停止整个无限序列的求值。

(defn fib [n]
   (nth (iterate (fn [[x y & _ :as all]] (cons (+ x y) all)) '(1 1)) (- n 2)))

另请注意,这会以与您的实现相反的顺序返回结果;当然,用 reverse 解决这个问题很简单。

编辑:或者实际上,正如 amalloy 所说,通过使用向量:

(defn fib [n]
   (nth (iterate (fn [all]
                   (conj all (->> all (take-last 2) (apply +)))) [1 1])
        (- n 2)))

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 function iterate sounds like it would be good for this:

user> (doc iterate)
-------------------------
clojure.core/iterate
([f x])
  Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects

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.

(fn [[x y & _ :as all]] (cons (+ x y) all))

The argument list here just means that x and y 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 via all.

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.

(defn fib [n]
   (nth (iterate (fn [[x y & _ :as all]] (cons (+ x y) all)) '(1 1)) (- n 2)))

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:

(defn fib [n]
   (nth (iterate (fn [all]
                   (conj all (->> all (take-last 2) (apply +)))) [1 1])
        (- n 2)))
你的背包 2024-12-11 01:26:06

请参阅 Stu Halloway 编写的Clojure 编程中的 Christophe Grand 斐波那契解决方案。这是我见过的最优雅的解决方案。

(defn fibo [] (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1])))
(take 10 (fibo))

另请参阅

如何使用生成斐波那契序列Clojure?

See Christophe Grand's Fibonacci solution in Programming Clojure by Stu Halloway. It is the most elegant solution I have seen.

(defn fibo [] (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1])))
(take 10 (fibo))

Also see

How can I generate the Fibonacci sequence using Clojure?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文