2013-04-25 3 views
11

Mi sto facendo conoscere ad Erlang da Armstrong "Programming Erlang". Un esercizio è scrivere una reeimplementazione della tuple_to_list/1 BIF. La mia soluzione mi sembra piuttosto poco elegante, soprattutto a causa della funzione di aiuto che uso. C'è un modo più Erlang-ish di fare questo?Erlang: elegante 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)]. 

Grazie mille per le vostre idee. :)

+1

prendere conoscenza che di le implementazioni di seguito sono ricorsive in coda. – Tilman

+3

Non c'è niente di sbagliato nell'avere funzioni di aiuto, spesso ne hai bisogno e sono il modo migliore di fare le cose. E non preoccuparti troppo della ricorsione in coda, vedi http://www.erlang.org/doc/efficiency_guide/listHandling.html#id64720 – rvirding

risposta

17

Penso che la tua funzione sia ok, e di più se il tuo obiettivo è imparare la lingua. Come una questione di stile, di solito il caso base nella costruzione di liste è solo la lista vuota []. Così mi piacerebbe scrivere

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

è possibile scrivere più o meno lo stesso con la lista di comprensione

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

che funzionerà come previsto quando la tupla non ha elementi, come elenchi: seguenti (1,0) dà una lista vuota.

+3

+1 per la comprensione delle liste. Mi piace l'uso delle liste: seq. Mi sento un po 'pitone. ;) – Zakum

7

Il tuo codice è buono e anche modo idiomatico su come realizzare questo tipo di cose. Puoi anche creare questo elenco a ritroso, che in questo caso sarà un po 'più veloce a causa della chiamata di coda ma non significativa.

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

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

Meglio usare 'tuple_size/1' invece di' size/1'. Vedi qui: http://erlang.org/doc/efficiency_guide/commoncaveats.html – coffeMug

2

In Erlang R16B è anche possibile usare erlang:delete_element/2 funzione come questa:

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

+1 per eliminare la funzione di supporto e la necessità di contatore e accumulatore. Ho letto che l'accelerazione della ricorsione della coda rispetto alla ricorsione della testa nelle versioni correnti è più una questione di architettura del processore *, quindi ho smesso come questa soluzione! * http: //www.erlang.org/doc/efficiency_guide/myths.html – Zakum

+4

-1 per una soluzione che crea una nuova tupla quando un elemento viene aggiunto all'elenco. Ricorda che non ci sono dati mutabili in erlang e 'erlang: delete_element/2' crea una nuova tupla! – rvirding

+0

@Zakum: dovresti leggere più attentamente questa mitizzazione demistificazione. _ la funzione lista ricorsiva del corpo e la funzione ricorsiva della coda che chiama 'liste: reverse/1' alla fine userà esattamente la stessa quantità di memoria_ Si noti la' liste: reverse/1' che la mia versione non fa. La versione ricorsiva della mia coda sarà sicuramente più veloce della [riconduttiva] [ppolv] (http://stackoverflow.com/users/171116/ppolv) [soluzione] (http://stackoverflow.com/a/16222818/49197), nessun dubbio. Ma quando la maggior parte delle tuple sono piccole ti non importa. Ma conosci la differenza. –

0

Erlang 17,0, si dovrebbe costruire la lista in ordine naturale, soluzioni sopra non è corretto dal punto di efficienza. aggiungere sempre elementi alla testa di una lista esistente:

%% ==================================================================== 
%% 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

Sto tentando esercizi da Joe Armstrong libro, Ecco quello che mi è venuta

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