如何在Erlang中生成整数范围?

31

在我使用其他编程语言时,通常会用到范围(range)这个概念。在 Python 中,如果我想要表示 1 到 100 的所有数字,我会写 range(1, 101);在 Haskell 中,我会写 [1..100];在 Scala 中,我会写 1 to 100

但是在 Erlang 中,无论是语法还是标准库中,似乎都没有相似的东西。虽然我知道自己可以比较容易地实现这个功能,但我希望先确认一下是否存在其他方法(特别是因为标准库或者语言本身实现的效率会更高)。

我的问题是:在 Erlang 中,是否有类似于“范围”的概念或者标准库函数可供使用?或者我是否忽略了某些惯用语言表达方式?我想知道我是否需要自己来实现这个功能。

当然,我也不排斥可能不应该在 Erlang 中使用“范围”这个概念(毕竟 Erlang 和 Python、Haskell 差别很大)。另外,如果我确实需要自己实现这个功能,如果您有任何提高性能的好建议,我也非常愿意听取。


很难说你是否做错了事情。你只是说了你尝试如何去做某件事,而没有说你想要做什么。 - Dustin
@Dustin 我的意思是,我想知道我在 Erlang 中是否没有正确思考。 - Rafe Kettler
正如btilly所指出的那样,lists:seq/2是最佳选择!我通常会推荐查看lists模块,它非常强大。噢,还要看一下http://www.erldocs.com。 - E Dominique
如果你不告诉我们你在想什么,我们就无法确定你是否正确地考虑了某件事情。虽然有实现你所要求的确切功能的方法,但这并不意味着它是你尝试做任何事情的正确方式。也许是。但是缺乏足够的信息来做出判断。 - Dustin
4个回答

57

13
你可以使用list:seq(From, TO),这是@bitilly所说的,也可以使用列表理解式来添加更多功能,例如:
1> [X || X <- lists:seq(1,100), X rem 2 == 0].
[2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,
 44,46,48,50,52,54,56,58|...]

2

在Ruby中,range和Erlang中的list:seq之间有区别。Ruby的range不会创建列表,并依赖于next方法,因此(1..HugeInteger).each { ... }不会消耗内存。而我相信Erlang的lists:seq会创建列表。因此,当range用于副作用时,确实会有所不同。

附注:不仅仅是用于副作用:

(1..HugeInteger).inject(0) { |s, v| s + v % 1000000 == 0 ? 1 : 0 }

将以与每个相同的方式工作,不创建列表。Erlang 的解决方案是创建递归函数。实际上,这本质上是一个隐式循环。


是的,Erlang 没有惰性求值的手段。 - Rafe Kettler
1
@Rafe 当然可以!只需要使用函数。 - Daniel Yankowsky
@Daniel 诅咒我对这门语言过早的评判。我应该更深入地阅读教程。 - Rafe Kettler
@DanielYankowsky,您如何在Erlang中使用函数实现惰性流?假设我们需要惰性地迭代范围[1..100]中的所有奇数。 - Sharas
@Sharas 快速的答案是使用生成器函数,它可以根据流中的值产生下一个值。因此,“惰性列表”将是一个元组,包含{初始值,生成器函数}。如果这还不够强大,您可以让生成器函数生成整个流的尾部...(作为一个流本身),这将是一个元组,包含{初始值,生成器函数}。当然,没有内置的列表函数可以在这样的流上工作,所以您需要实现您需要的函数。要获取更多信息,请在SO上发布一个新问题...有人会回答的。 - Daniel Yankowsky

1

这是Erlang中懒惰流的示例。虽然不是Erlang特有的,但我认为它可以在任何具有lambda的语言中完成。每次流推进时都会创建一个新的lambda,因此可能会对垃圾收集器造成一些压力。

range(From, To, _) when From > To ->
    done;
range(From, To, Step) ->
    {From, fun() -> range(From + Step, To, Step) end}.

list(done) ->
    [];
list({Value, Iterator}) ->
    [Value | list(Iterator())].

% ----- usage example ------

list_odd_numbers(From, To) ->
    list(range(From bor 1, To, 2)).

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接