以下是在Clojure和Python中可以找到的Fibonacci数的无限懒序列的最佳实现:
Clojure公司:
(def fib-seq (lazy-cat [0 1]
(map + fib-seq (rest fib-seq))))
示例用法:
(take 5 fib-seq)
Python:
def fib():
a = b = 1
while True:
yield a
a,b = b,a+b
示例用法:
for i in fib():
if i > 100:
break
else:
print i
显然,Python代码更直观。
我的问题是:Clojure中是否有更好(更直观和简单)的实现?
我想问一个后续问题 Clojure Prime Numbers
我同意帕维尔的观点,直觉是主观的。因为我(慢慢地)开始grok Haskell,我可以知道Clojure代码是做什么的,即使我这辈子从未写过Clojure代码。因此,我认为Clojure系列相当直观,因为我以前见过它,我正在适应一种更具功能性的思维方式。
让我们考虑一下数学上的定义,好吗?
这不太理想,从格式上看-这三个括号应该是一个大括号-但是谁在计算呢?对于大多数有数学背景的人来说,这是斐波那契数列的一个非常明确的定义。让我们看看哈斯克尔的相同之处,因为我比克洛朱尔更了解它:
这是一个函数
fib
,它返回第n个斐波那契数。不完全是我们在Python或Clojure中所拥有的,所以让我们修正一下:这使得
fibs
成为一个无限的Fibonacci数列表。fibs !! 1
是1,fibs !! 2
是1,fibs !! 10
是55,依此类推。然而,这可能是非常低效的,即使是在一种依赖于高度优化递归的语言中,比如Haskell。让我们看看Haskell中的Clojure定义:前两个字符非常简单:
0 : 1 :
生成一个包含元素0和1的列表,然后是更多的元素。但剩下的是什么?好吧,fibs
是我们已经得到的列表,到目前为止,tail fibs
调用列表中的tail
函数,它返回从第二个元素开始的列表(类似于Python中说的fibs[1:]
)。所以我们把这两个列表-fibs
和tail fibs
-和+
函数(操作符)压缩在一起,也就是说,我们添加每个列表的匹配元素。让我们看看:所以我们的下一个元素是1!但是,然后我们将其添加回我们的
fibs
列表中,看看我们得到了什么:这里有一个递归列表定义。当我们使用
zipWith (+) fibs (tail fibs)
位在fibs
结尾添加更多元素时,在添加元素时可以使用更多元素。注意Haskell在默认情况下是懒惰的,所以创建这样的无限列表不会崩溃任何东西(只是不要试图打印它)。因此,虽然这在理论上可能与我们之前的数学定义相同,但它将结果保存在我们的
fibs
列表(某种程度上是一种自动记忆)中,而且我们很少遇到在天真的解决方案中可能遇到的问题。为了完整起见,让我们根据新的fibs
列表定义fib
函数:如果我还没有失去你,那很好,因为那意味着你理解Clojure代码。看:
我们列一个清单,
fib-seq
。它以两个元素[0 1]
开始,就像我们的Haskell示例一样。我们用(map + fib-seq (rest fib-seq))
对这两个初始元素进行延迟连接-假设rest
与tail
在Haskell中所做的相同,我们只是在较低的偏移量处将列表与自身组合,然后将这两个列表与+
运算符/函数组合。在你的头脑中思考了几次,并探索了一些其他的例子之后,这种生成斐波那契级数的方法至少变得半直观了。这至少直觉足以让我用一种我不知道的语言来识别它。
如果你不知道任何命令式语言,这对你来说是直观的吗?
世界贸易基金会?
a
显然与a + 5
不同。如果
a = a + 5
,那么a + 5 = a
?为什么这不管用???
有很多事情是不清楚的,除非你以前在其他地方看到过,并了解它的目的。很长一段时间我都不知道
yield
关键字,实际上我不知道它做了什么。您认为命令式方法更容易理解,因为您已经习惯了它。
我喜欢:
它似乎与python/generator版本有一些相似之处。
相关问题 更多 >
编程相关推荐