2013-04-25 9 views
11

Przedstawiam się Erlangowi przez Armstrongs "Programming Erlang". Jednym z ćwiczeń jest napisanie reeimplementacji tuple_to_list/1 BIF. Moje rozwiązanie wydaje mi się raczej nieeleganckie, szczególnie z powodu funkcji pomocnika, której używam. Czy istnieje inny sposób na robienie tego Erlang?Erlang: elegancka tuple_to_list/1

tup2lis({}) -> []; 
tup2lis(T) -> tup2list_help(T,1,tuple_size(T)). 

tup2list_help(T,Size,Size) -> [element(Size,T)]; 
tup2list_help(T,Pos,Size) -> [element(Pos,T)|tup2list_help(T,Pos+1,Size)]. 

Dziękuję bardzo za Twoje pomysły. :)

+1

Bądź bardziej świadomy, które z poniższe implementacje są rekursywne. – Tilman

+3

Nie ma nic złego w funkcjach pomocniczych, często ich potrzebujesz i są one najlepszym sposobem robienia rzeczy. I nie przejmuj się rekurencją ogona, zobacz http://www.erlang.org/doc/efficiency_guide/listHandling.html#id64720 – rvirding

Odpowiedz

17

Myślę, że twoja funkcja jest w porządku, a więcej, jeśli twoim celem jest nauka języka. Co do stylu, zazwyczaj podstawową budową list jest tylko pusta lista []. Więc będę pisać

tup2list(Tuple) -> tup2list(Tuple, 1, tuple_size(Tuple)). 

tup2list(Tuple, Pos, Size) when Pos =< Size -> 
    [element(Pos,Tuple) | tup2list(Tuple, Pos+1, Size)]; 
tup2list(_Tuple,_Pos,_Size) -> []. 

można napisać prawie to samo z listowego

[element(I,Tuple) || I <- lists:seq(1,tuple_size(Tuple))]. 

będzie działać zgodnie z oczekiwaniami, gdy krotka nie ma elementów, jak listy SEQ (1,0) daje pustą listę.

+3

+1 dla zrozumienia list. Lubię korzystać z list: seq. Dla mnie jest to trochę pytona. ;) – Zakum

7

Twój kod jest dobry, a także idiomatyczny sposób tworzenia tego rodzaju rzeczy. Możesz także zbudować tę listę wstecz, która w tym przypadku będzie trochę szybsza z powodu wywołania ogona, ale nieistotna.

tup2list(T) -> tup2list(T, size(T), []). 

tup2list(T, 0, Acc) -> Acc; 
tup2list(T, N, Acc) -> tup2list(T, N-1, [element(N,T)|Acc]). 
+1

Lepiej używać 'tuple_size/1' zamiast' size/1'. Zobacz tutaj: http://erlang.org/doc/efficiency_guide/commoncaveats.html – coffeMug

2

W Erlang R16B można również użyć erlang:delete_element/2 funkcję tak:

tuple2list({}) -> []; 
tuple2list(T) when is_tuple(T) -> 
    [element(1, T) | tuple2list(erlang:delete_element(1, T))]. 
+0

+1 za pozbycie się funkcji pomocnika i zapotrzebowanie na licznik i akumulator. Czytałem, że przyspieszenie rekurencji ogona w porównaniu z rekurencją czołową w aktualnych wersjach jest bardziej kwestią architektury procesora *, więc opuściłem to rozwiązanie! * http: //www.erlang.org/doc/efficiency_guide/myths.html – Zakum

+4

-1 dla rozwiązania, które tworzy nową krotkę, gdy element zostanie dodany do listy. Pamiętaj, że w erlangu nie ma zmienionych danych, a 'erlang: delete_element/2' tworzy nową krotkę! – rvirding

+0

@Zakum: Powinieneś uważniej przeczytać tę demistyfikację mitu. _-rekursywna funkcja listy i funkcja rekursywna ogona, która wywołuje 'list: reverse/1' na końcu, użyje dokładnie takiej samej ilości pamięci_ Zauważ, że' list: reverse/1' której nie ma w mojej wersji. Wersja rekursywna ogona kopalni zdecydowanie będzie szybsza niż rozwiązanie rekursywne [ppolv] (http://stackoverflow.com/users/171116/ppolv) [http://stackoverflow.com/a/16222818/49197], bez wątpienia. Ale kiedy większość krotek jest mała, ti nie ma znaczenia. Ale poznaj różnicę. –

0

Erlang 17,0, należy zbudować listę w porządku naturalnego, rozwiązania powyżej jest błędne z punktu skuteczności. Zawsze dodawać elementy do głowy istniejącej listy:

%% ==================================================================== 
%% API functions 
%% ==================================================================== 
my_tuple_to_list({}) -> 
    []; 
my_tuple_to_list(Tuple) -> 
    tuple_to_list_iter(1, size(Tuple), Tuple, []) 
. 
%% ==================================================================== 
%% Internal functions 
%% ==================================================================== 
tuple_to_list_iter(N, N, Tuple, List) -> 
    lists:reverse([element(N, Tuple)|List]); 

tuple_to_list_iter(N, Tuplesize, Tuple, List) -> 
    L = [element(N, Tuple)|List], 
    tuple_to_list_iter(N + 1, Tuplesize, Tuple, L)  
. 
0

mytuple_to_list(T) when tuple_size(T) =:= 0 -> []; mytuple_to_list(T) -> [element(1, T)|mytuple_to_list(erlang:delete_element(1, T))].

3

jestem próby ćwiczeń z Joe Armstrong książce Oto co wymyśliłem

my_tuple_to_list(Tuple) -> [element(T, Tuple) || T <- lists:seq(1, tuple_size(Tuple))].