수색…


통사론

  • function (list | iolist | tuple) -> function (tail).

비고

왜 재귀 함수입니까?

Erlang은 함수형 프로그래밍 언어이며 어떤 종류의 루프 구조도 아닙니다. 함수형 프로그래밍의 모든 것은 데이터, 유형 및 함수를 기반으로합니다. 루프를 원한다면, 스스로를 호출하는 함수를 생성해야합니다.

Erlang의 명령형 또는 객체 지향 언어의 전통적인 while 또는 for 루프는 다음과 같이 표현할 수 있습니다.

loop() ->
  % do something here
  loop().

이 개념을 이해하는 좋은 방법은 모든 함수 호출을 확장하는 것입니다. 우리는 다른 예를 보게 될 것입니다.

명부

여기는 목록 유형에 대한 가장 간단한 재귀 함수입니다. 이 함수는 처음부터 끝까지 목록으로 이동하고 더 이상 아무것도 수행하지 않습니다.

-spec loop(list()) -> ok.
loop([]) ->
  ok;
loop([H|T]) ->
  loop(T).

다음과 같이 호출 할 수 있습니다.

loop([1,2,3]). % will return ok.

여기 재귀 함수 확장 :

loop([1|2,3]) ->
  loop([2|3]) ->
    loop([3|]) ->
      loop([]) ->
        ok.

IO 작업을 사용하는 순환 루프

이전 코드는 아무 것도하지 않고 꽤 쓸모가 없습니다. 이제 우리는 몇 가지 작업을 수행하는 재귀 함수를 작성합니다. 이 코드는 lists:foreach/2 과 유사 lists:foreach/2 .

-spec loop(list(), fun()) -> ok.
loop([], _) ->
  ok;
loop([H|T], Fun) 
  when is_function(Fun) ->
    Fun(H),
    loop(T, Fun).

다음과 같이 호출 할 수 있습니다.

Fun = fun(X) -> io:format("~p", [X]) end.
loop([1,2,3]).

여기 재귀 함수 확장 :

loop([1|2,3], Fun(1)) ->
  loop([2|3], Fun(2)) ->
    loop([3|], Fun(3)) ->
      loop([], _) ->
        ok.

lists:foreach/2 과 비교할 수 있습니다 lists:foreach/2 출력 :

lists:foreach(Fun, [1,2,3]).

수정 된 목록을 반환하는 목록에 대한 순환 루프

또 다른 유용한 예는 lists:map/2 와 유사합니다. 이 함수는 하나의 목록과 하나의 익명 함수를 취합니다. list에있는 값이 매번 매번 함수에 적용됩니다.

-spec loop(A :: list(), fun()) -> list().
loop(List, Fun) 
  when is_list(List), is_function(Fun) ->
    loop(List, Fun, []).

-spec loop(list(), fun(), list()) -> list() | {error, list()}.
loop([], _, Buffer) 
  when is_list(Buffer) ->
    lists:reverse(Buffer);
loop([H|T], Fun, Buffer) 
  when is_function(Fun), is_list(Buffer) ->
    BufferReturn = [Fun(H)] ++ Buffer,
    loop(T, Fun, BufferReturn).

다음과 같이 호출 할 수 있습니다.

Fun(X) -> X+1 end.
loop([1,2,3], Fun).

여기 재귀 함수 확장 :

loop([1|2,3], Fun(1), [2]) ->
  loop([2|3], Fun(2), [3,2]) ->
    loop([3|], Fun(3), [4,3,2]) ->
      loop([], _, [4,3,2]) ->
        list:reverse([4,3,2]) ->
          [2,3,4].

이 함수는 누적 기와 같은 변수를 사용하여 여러 실행 컨텍스트에서 수정 된 데이터를 전달하기 때문에 "꼬리 재귀 함수"라고도합니다.

아이 솔리스트와 비트 스트링

목록과 마찬가지로 iolist 및 bitstring에 대한 가장 간단한 함수는 다음 같습니다.

-spec loop(iolist()) -> ok | {ok, iolist} .
loop(<<>>) ->
  ok;
loop(<<Head, Tail/bitstring>>) ->
  loop(Tail);
loop(<<Rest/bitstring>>) ->
  {ok, Rest}

다음과 같이 호출 할 수 있습니다.

loop(<<"abc">>).

여기 재귀 함수 확장 :

loop(<<"a"/bitstring, "bc"/bitstring>>) ->
  loop(<<"b"/bitstring, "c"/bitstring>>) ->
    loop(<<"c"/bitstring>>) ->
      loop(<<>>) ->
        ok.

가변 바이너리 크기에 걸친 재귀 함수

이 코드는 bitstring을 가져 와서 이진 크기를 동적으로 정의합니다. 만약 우리가의 크기로 설정하면, 44 비트는 데이터가 일치한다. 이 루프는 재미있는 일이 아닙니다. 그저 기둥 일뿐입니다.

loop(Bitstring, Size) 
  when is_bitstring(Bitstring), is_integer(Size) ->
    case Bitstring of
      <<>> -> 
        ok;
      <<Head:Size/bitstring,Tail/bitstring>> ->
        loop(Tail, Size);
      <<Rest/bitstring>> ->
        {ok, Rest}
    end.

다음과 같이 호출 할 수 있습니다.

loop(<<"abc">>, 4).

여기 재귀 함수 확장 :

loop(<<6:4/bitstring, 22, 38, 3:4>>, 4) ->
  loop(<<1:4/bitstring, "bc">>, 4) ->
    loop(<<6:4/bitstring, 38,3:4>>, 4) ->
      loop(<<2:4/bitstring, "c">>, 4) ->
        loop(<<6:4/bitstring, 3:4>>, 4) ->
          loop(<<3:4/bitstring>>, 4) ->
            loop(<<>>, 4) ->
              ok.

우리의 bitstring은 7 패턴 이상 splitted 있습니다. 왜? 기본적으로 Erlang은 8 비트의 바이너리 크기를 사용하기 때문에, 2로 나누면 4 비트가됩니다. 우리의 문자열은 8*3=24 비트입니다. 24/4=6 패턴. 마지막 패턴은 <<>> 입니다. loop/2 함수는 7 번 호출됩니다.

동작이있는 가변 바이너리 크기에 대한 재귀 함수

이제 우리는 더 재미있는 일을 할 수 있습니다. 이 함수는 익명 함수 인 인수를 하나 더 사용합니다. 우리가 패턴과 매치 할 때마다이 패턴이 패턴에 전달됩니다.

-spec loop(iolist(), integer(), function()) -> ok.
loop(Bitstring, Size, Fun) ->
  when is_bitstring(Bitstring), is_integer(Size), is_function(Fun) ->
        case Bitstring of
      <<>> -> 
        ok;
      <<Head:Size/bitstring,Tail/bitstring>> ->
        Fun(Head),
        loop(Tail, Size, Fun);
      <<Rest/bitstring>> ->
        Fun(Rest),
        {ok, Rest}
    end.

다음과 같이 호출 할 수 있습니다.

Fun = fun(X) -> io:format("~p~n", [X]) end.
loop(<<"abc">>, 4, Fun).

여기 재귀 함수 확장 :

loop(<<6:4/bitstring, 22, 38, 3:4>>, 4, Fun(<<6:4>>) ->
  loop(<<1:4/bitstring, "bc">>, 4, Fun(<<1:4>>)) ->
    loop(<<6:4/bitstring, 38,3:4>>, 4, Fun(<<6:4>>)) ->
      loop(<<2:4/bitstring, "c">>, 4, Fun(<<2:4>>)) ->
        loop(<<6:4/bitstring, 3:4>>, 4, Fun(<<6:4>>) ->
          loop(<<3:4/bitstring>>, 4, Fun(<<3:4>>) ->
            loop(<<>>, 4) ->
              ok.

수정 된 비트 문자열을 반환하는 비트 문자열에 대한 재귀 함수

이 것은 lists:map/2 와 유사하지만 bitstring과 iolist에 해당합니다.

% public function (interface).
-spec loop(iolist(), fun()) -> iolist() | {iolist(), iolist()}.
loop(Bitstring, Fun) ->
  loop(Bitstring, 8, Fun).

% public function (interface).
-spec loop(iolist(), integer(), fun()) -> iolist() | {iolist(), iolist()}.
loop(Bitstring, Size, Fun) ->
  loop(Bitstring, Size, Fun, <<>>)

% private function.
-spec loop(iolist(), integer(), fun(), iolist()) -> iolist() | {iolist(), iolist()}.
loop(<<>>, _, _, Buffer) ->
  Buffer;
loop(Bitstring, Size, Fun, Buffer) ->
  when is_bitstring(Bitstring), is_integer(Size), is_function(Fun) ->
    case Bitstring of
      <<>> -> 
        Buffer;
      <<Head:Size/bitstring,Tail/bitstring>> ->
        Data = Fun(Head),
        BufferReturn = <<Buffer/bitstring, Data/bitstring>>,
        loop(Tail, Size, Fun, BufferReturn);
      <<Rest/bitstring>> ->
        {Buffer, Rest}
    end.

이 코드는 더 복잡해 보입니다. loop/2loop/3 두 가지 기능이 추가되었습니다. 이 두 함수는 loop/4 대한 간단한 인터페이스입니다.

다음과 같이 실행할 수 있습니다.

Fun = fun(<<X>>) -> << (X+1) >> end.
loop(<<"abc">>, Fun).
% will return <<"bcd">>

Fun = fun(<<X:4>>) -> << (X+1) >> end.
loop(<<"abc">>, 4, Fun).
% will return <<7,2,7,3,7,4>>

loop(<<"abc">>, 4, Fun, <<>>).
% will return <<7,2,7,3,7,4>>

지도

얼랭 (Erlang)의 Map 은 Perl의 해시 또는 키 / 값 저장소 인 Python의 사전 에 해당합니다. 저장된 모든 값을 나열하려면 모든 키를 나열하고 키 / 값 쌍을 리턴하십시오. 이 첫 번째 루프는 아이디어를 제공합니다.

loop(Map) when is_map(Map) -> 
  Keys = maps:keys(Map),
  loop(Map, Keys).

loop(_ , []) ->
  ok;
loop(Map, [Head|Tail]) ->
  Value = maps:get(Head, Map),
  io:format("~p: ~p~n", [Head, Value]),
  loop(Map, Tail).

다음과 같이 실행할 수 있습니다.

Map = #{1 => "one", 2 => "two", 3 => "three"}.
loop(Map).
% will return:
% 1: "one"
% 2: "two"
% 3: "three"

주 관리

재귀 함수는 루프의 상태를 사용합니다. 새 프로세스를 생성 할 때이 프로세스는 정의 된 상태의 루프 일뿐입니다.

익명 기능

앞의 예제에 기반한 재귀 익명 함수 의 2 가지 예입니다. 첫째, 단순한 무한 루프 :

InfiniteLoop = fun 
  R() -> 
    R() end.

둘째, 익명 함수가 목록에서 루프를 수행함 :

LoopOverList = fun 
  R([]) -> ok;
  R([H|T]) ->
    R(T) end.

이 두 함수는 다음과 같이 재 작성 될 수 있습니다.

InfiniteLoop = fun loop/0.

이 경우 loop/0 은 비고에서 오는 loop/0 에 대한 참조입니다. 둘째로, 조금 더 복잡한 것은 :

LoopOverLlist = fun loop/2.

여기서, loop/2 에 대한 참조 loop/2 리스트 예의. 이 두 표기법은 통사론적인 설탕입니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow