Erlang: 跳出lists:foreach“循环”

5

我有一个Erlang元素列表,并且我正在使用lists:foreach遍历列表中的元素。是否有一种方法可以在遍历过程中退出这个“foreach循环”。例如:假设如果我在列表[2, 4, 5, 1, 2, 5]中遇到了'1',那么我想停止遍历该列表。我该怎么做?

5个回答

8

另一种方法是使用 throwcatch

catch lists:foreach(
        fun(1) ->
                throw(found_one);
           (X) ->
                io:format("~p~n", [X])
        end,
        [2, 4, 5, 1, 2, 5]).

在Shell中运行时,这将输出:
2
4
5
found_one

编辑: 受欢迎需求的影响,这里提供一个更精确的版本,只捕获您想要捕获的内容:

try lists:foreach(
        fun(1) ->
                throw(found_one);
           (X) ->
                io:format("~p~n", [X])
        end,
        [2, 4, 5, 1, 2, 5])
catch
    throw:found_one ->
        found_one
end.

1
使用异常抛出应该是函数的“非局部返回”。在这个答案中的使用是有效的异常抛出用法,我不明白为什么会被踩。 - Hynek -Pichi- Vychodil
在Python社区中有一句话:“这个解决方案不是很Pythonic”。在Erlang社区中是否有类似的表达方式呢?;-) - jldupont
1
异常应该用于指示异常情况,而不是用于流程控制。 - Dónal
2
throw 本身并不是一个异常。它确实应该用于流程控制。请参考 Erlang 的参考指南。 - gleber
3
如果io:format抛出了异常,你该如何处理"意外"异常?在这个简单的例子中,如果出现这种或那种类型的异常,你需要做好准备。将其改写成case catch或try catch语句,情况就不会再那么简单了... - Zed

7
traverse(Liste) ->
 traverse(Liste, []).

traverse([], Acc) ->
 Acc;    

traverse([1|_], Acc) ->
 Acc;

traverse([H|T], Acc) ->
 % do something useful here maybe?
 traverse(T, Acc).

当然,这只是一个非常粗略的例子。

是的,我经常发现理解像lists:foreach这样的东西然后编写自己的版本以满足特殊情况更容易。正如您在上面看到的,代码行数微不足道。浏览lists模块源代码将为Erlang语言及其使用提供很多见解... - Alan Moore
我的看法也是如此:一旦您熟悉了Erlang,这种表现力将会产生神奇的效果。 - jldupont
我想知道这个函数是否会返回除 [] 之外的任何内容(不包括没有匹配的函数子句 :o)) - Zed
@zed:当然,这取决于你在“这里可能做一些有用的事情”部分放了什么。 “Acc”作为“累加器”。来吧,Zed,已经很晚了;-) - jldupont
好的解决方案,但我花了一些时间才理解。如果你不知道 Erlang 函数重载,那么必须查看 http://erlang.org/doc/reference_manual/functions.html。 - user1418225

3

lists模块中有许多很好的函数:

lists:foreach(fun(E) -> do_something(E) end,
    lists:takewhile(fun(E) -> E =/= 1 end, List)).

更有效但不太美观
lists:takewhile(fun(1) -> false;
                   (E) -> do_something(E), true
                end, List)

当我遇到1时,我需要停止进一步处理列表,而不仅仅是跳过1。 - ErJab
@ErJab:所以请看RTFM http://erlang.org/doc/man/lists.html#takewhile-2,而不是http://erlang.org/doc/man/lists.html#filter-2。你认为它是如何工作的?继续处理列表只是为了好玩吗? - Hynek -Pichi- Vychodil

1

列表:全部?

do_something(A) ->
   case A of 
      1 ->
         false;
      _ ->
         true
   end.

IsCompleted = lists:all(do_something(A), [2, 4, 5, 1, 2, 5]),

每当 do_something 返回 false 时,IsCompleted 就会被触发并返回结果。

1

我遇到了同样的问题,并通过以下方式解决:

-module(foreach_until).
-export([foreach_until/3]).

foreach_until(Action, L, Judge)     ->
    lists:reverse(foreach_until(Action, L, Judge, []))
    .

foreach_until(_, [], _, Result) ->
    Result
    ;

foreach_until(Action, [H | T], Judge, Result)   ->
    case Judge(H) of 
        true    -> Result;
        false   -> foreach_until(Action, T, Judge, [Action(H) | Result])
    end
    .

以下是一个示例,解释了如何使用:

下面是一个解释如何使用的示例:

60> foreach_until:foreach_until(fun(X) -> X*X end, [1,2,3,4], fun(X)-> X >= 3 end).
[1,4]

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