2010-07-19 2 views
5

얼랑 (Erlang)에서 일반적인 디자인 패턴 인 코딩 문제가 있지만 해결 방법에 대한 정보를 찾을 수 없습니다.디자인 패턴? 함수는 첫 번째 {success} 결과를 검색하여 목록을 반복합니다.

리스트 L이 있습니다. L의 모든 요소에 함수 f를 적용하고 L의 모든 요소를 ​​동시에 실행하려고합니다. f (Element)에 대한 각 호출은 성공하거나 실패합니다. 대다수의 경우 실패 할 것이지만 때때로 L 내의 특정 요소에 대해 성공할 것입니다.

af (Element)가 성공할 경우 "성공"이 f의 모든 호출을 종료합니다. L의 다른 요소 - 첫 번째 "성공"은 내가 관심있는 부분입니다. 반면에 f (Element)가 L의 모든 요소에 대해 실패하면 "실패"를 반환하고 싶습니다.

예를 들어, L이 정수의 목록이고 F가 L의 요소가 3이면 {success}를 반환하고 다른 값의 경우 {fail}을 반환한다고 가정합니다. L에 3이 있으면 가능한 한 빨리 찾으려고합니다. 얼마나 많은 3이 존재하는지, 적어도 하나의 3이 존재하는지 여부는 상관하지 않습니다. f를 다음과 같이 수 :

f(Int) -> 
    case Int of 
    3 -> {success}; 
    _ -> {fail} 
    end. 
나는 목록이 하나 이상의 3가 포함되어 있는지 확인하고 가능한 한 빨리 돌아 INT의 목록을 반복 할 수 있습니까

?

은 분명히이 공통 기능적인 디자인 패턴, 그리고 난 그냥

답변

2

이미 답변 해 주셨습니다. 해결책은 목록을 사용하는 것입니다 : any/2. 은 "wait_for_children"프로세스가 종료 (have_result)를 수행 할 때 모든 아이들 ("실행"프로세스가) 죽을

any(F, List) -> 
    Parent = self(), 
    Pid = spawn(fun() -> spawner(Parent, F, List) end), 
    receive {Pid, Result} -> Result 
    end, 
    Result. 

spawner(Parent, F, List) -> 
    Spawner = self(), 
    S = spawn_link(fun() -> wait_for_result(Spawner, Parent, length(List)) end), 
    [spawn_link(fun() -> run(S, F) end) || X <- List], 
    receive after infinity -> ok end. 

wait_for_result(Spawner, Parent, 0) -> 
    Parent ! {Spawner, false}, 
    exit(have_result); 
wait_for_result(Spawner, Parent, Children) -> 
    receive 
    true -> Parent ! {Spawner, true}, exit(have_result); 
    false -> wait_for_result(Spawner, Parent, Children -1) 
    end. 

run(S, F) -> 
    case catch(F()) of 
    true -> S ! true; 
    _ -> S ! false 
    end. 

참고 :

당신이 그것의 동시 버전을한다고 본다.

완전히 테스트되지 않았습니다 ... 아, 도대체 뭐야. 예를 들어 보겠습니다 :

4> play:any(fun(A) -> A == a end, [b,b,b,b,b,b,b,b]). 
false 
5> play:any(fun(A) -> A == a end, [b,b,b,b,b,b,a,b]). 
true 

버그가있을 수 있습니다 (있을 수 있습니다).

+0

'wait_for_result/2'에서 어떤 worker가'false'를 리턴하는지에 관심이 없다는 것을 알면 이것을 최적화 할 수 있습니다. 따라서 매번 목록의 첫 번째 요소를 제거하면 충분합니다. – rvirding

+0

'exit (have_result)'를 실행하면 남아있는 모든 작업자 프로세스가 링크 될 때 ('spawn_link'로 시작됨)'has_result'가'normal'이 아니므로 종료 될 것이므로 오류 종료로 처리해야 함을 언급해야합니다. – rvirding

+0

당신은 물론 맞습니다. 의견에 대한 답변을 업데이트했습니다. –

4

이 일을 기본적으로 두 가지 방법 ... 구글 내에서 올바른 검색어를 사용하지 않는. 어느 목록을 반복이 발견 여부에 따라 true 또는 false을 돌려 자신의 함수를 작성 3 :

contains_3([3|_]) -> true; 
contains_3([_|T]) -> contains_3(T); 
contains_3([]) -> false. 

두 번째 목록 요소에서 테스트 할 때까지 실제 반복을 수행하는 A 이미 정의 된 함수를 사용하는 것입니다 사실이고 시험을 제공합니다. lists:any 반환 테스트가 적어도 하나의 요소에 대한 성공 여부에 따라 true 또는 false :

contains_3(List) -> lists:any(fun (E) -> E =:= 3 end, List). 

이 같은 일을 할 것입니다. 당신이 선택한 것은 당신에게 달렸습니다. 두 번째 것은 아마도 디자인 패턴에 더 가깝지만, 사용하더라도 내부적으로 어떻게 작동하는지 생각해야합니다. 이 경우 그것은 사소하고 명백한 경우에 매우 가깝습니다.

매우 일반적인 일이지만, 내가 잘 모르는 디자인 패턴으로 분류 할 것인지 여부. 그것은 매우 기본적이고 어떤 의미에서 "사소한"것처럼 보이기 때문에 나는 그것을 디자인 패턴이라고 부르는 것을 주저합니다.

+0

감사합니다. 내 예제가 너무 사소한 것처럼 보입니다 ... 목록의 각 요소에 대해 실행해야하는 상당히 복잡하고 시간 소모적 인 기능이 있습니다. 목록의 각 요소에 대해 동시에 실행하고 싶기 때문에 가능한 한 빨리 {success} 결과를 얻을 수 있습니다. 그러나 첫 번째 {성공}을 얻은 후에는 다른 모든 요소에 대해 계속 기능을 수행해야 할 필요가 없습니다. 너무 오래 걸릴 것이고 너무 많은 리소스를 씹어 서 아무런 이익이 없습니다. 마지막으로, 목록 요소에 대해 {success}가없는 경우이를 인식해야합니다. – monch1962

+0

나는 예를 들어 주위에 기반을 둔 해결책이 있기를 바라고 있습니다. 여러 함수 (하나의 목록 요소 당 하나씩)를 생성하여 동시에 실행하게 한 다음 {success} 또는 {fail}을 부모 프로세스로 되돌려 보냅니다. 부모 프로세스에서 실행되는 목록 이해 및 수신 루프를 사용하여 쉽게 구축 할 수 있습니다. (a)받은 첫 번째 {성공}에 대해 다른 하위 프로세스에게 처리를 중지하고 최대한 빨리 종료하도록 알리고 (b) 모든 하위 프로세스의 결과가 {실패} 인 경우를 처리하므로 부모는 결코 볼 수 없습니다 성공}. – monch1962

3

내가 어떤 얼랑 (erlang)을 한 지 오래되었으므로 구문을 제공하려고하지는 않습니다. 그러나 erlang과 OTP는 해결책을 기다리고 있습니다.

함수를 나타내는 하나의 프로세스를 생성합니다. 요소별로 계산을 효율적으로 수행하는 것이 적절하다고 느끼는만큼 많은 프로세스를 생성하여 목록을 반복합니다.

모든 프로세스를 function-process에 연결하고 첫 번째 결과를 반환 한 후 함수 프로세스를 종료하게하십시오.

erlang/otp가 나머지 프로세스를 정리하도록하십시오.

+0

그것은 많은 의미가 있습니다 - 나는 그것을 나중에 나중에 시도 할 것입니다. 제안을 주셔서 감사합니다 – monch1962

0

당신은 plists 모듈을보고 할 수 있습니다 : http://code.google.com/p/plists/plists:any가 처리하는 경우 나도 몰라하지만

(A) {성공}받은 1 일, 처리를 중지 다른 하위 프로세스에게 & 즉시 끝내기

관련 문제