2009-11-30 2 views
4

У меня есть список элементов в Erlang, и я использую списки: foreach для перемещения по элементам в списке. Есть ли способ вырваться из этой «петли foreach» в середине обхода. Например: предположим, что я хочу продолжить перемещение списка, если я столкнулся с «1» в списке [2, 4, 5, 1, 2, 5]. Как мне это сделать?Erlang: Нарушение списков: foreach «loop»

ответ

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

traverse([], Acc) -> 
Acc;  

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

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

Конечно, это очень грубый пример.

+0

Да, я часто нахожу, что легче понять, как что-то вроде списков: foreach работает, а затем писать собственную версию, чтобы обслуживать особые случаи. Как вы можете видеть выше, количество строк кода тривиально. Просмотр исходного кода модуля списков даст много понимания языка Erlang и его использования ... –

+0

Мое чувство тоже: как только вам понравится Эрланг, такая выразительность творит чудеса. – jldupont

+0

Интересно, если это когда-либо возвращает ничего, кроме [] (не считая никакого соответствующего предложения функции: o)) – Zed

8

Другой способ сделать это состоит в использовании throw и catch:

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

При запуске в оболочке, эти выходы:

2 
4 
5 
found_one 

EDIT: По многочисленным просьбам, более точное версия, которая улавливает только то, что вы хотите поймать:

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

Использование исключения throw должно быть «не локальным возвратом» из функции. Использование в этом ответе является допустимым использованием броска, и я не понимаю, почему он тогда проголосовал. –

+0

В сообществе Python есть высказывание «это решение не очень * Pythonic *». Есть ли эквивалентное выражение в сообществе Erlang? ;-) – jldupont

+1

Исключения должны использоваться для указания исключительных условий, а не для управления потоком. –

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) 
+0

Мне нужно прекратить обработку списка furthur, когда я столкнулся с 1, а не просто пропустить 1. – ErJab

+0

@ErJab: Итак, RTFM http://erlang.org/doc/man/lists.html#takewhile-2 Это не http://erlang.org/doc/man/lists.html#filter-2 Как вы думаете, его работа? Продолжить обработку остальной части списка только для удовольствия? –

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] 
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.