Functional programming Erlang:优雅的元组到列表/1

Functional programming Erlang:优雅的元组到列表/1,functional-programming,erlang,Functional Programming,Erlang,我将通过Armstrong的“编程Erlang”介绍自己认识Erlang。一个练习是编写tuple_to_list/1bif的一个实现。我的解决方案对我来说似乎很不雅观,特别是因为我使用了helper函数。有没有更像Erlang的方法 tup2lis({}) -> []; tup2lis(T) -> tup2list_help(T,1,tuple_size(T)). tup2list_help(T,Size,Size) -> [element(Size,T)]; tup2li

我将通过Armstrong的“编程Erlang”介绍自己认识Erlang。一个练习是编写tuple_to_list/1bif的一个实现。我的解决方案对我来说似乎很不雅观,特别是因为我使用了helper函数。有没有更像Erlang的方法

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

非常感谢您的想法。:)

我认为你的功能还可以,如果你的目标是学习这门语言,那就更重要了。 就风格而言,通常在构建列表时,基本情况只是空列表[]。 所以我会写信

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) -> [].
tup2list(Tuple)->tup2list(Tuple,1,Tuple\u size(Tuple))。
当Pos=
[元素(位置,元组)|元组列表(元组,位置+1,大小)];
tup2list(\u Tuple,\u Pos,\u Size)->[]。
你可以用列表理解来写几乎相同的东西

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

[element(I,Tuple)| I您的代码很好,而且是制作这类东西的惯用方法。您也可以向后构建此列表,在这种情况下,由于尾部调用,它会稍微快一点,但并不重要

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

tup2list(T, 0, Acc) -> Acc;
tup2list(T, N, Acc) -> tup2list(T, N-1, [element(N,T)|Acc]).
在中,您还可以使用如下功能:

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

Erlang 17.0,您应该按照自然顺序构建列表,从效率的角度来看,上述解决方案是不正确的。始终将元素添加到现有列表的开头:

%% ====================================================================
%% 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)    
.
mytuple\u to\u list(T)当tuple\u size(T)=:=0->[];

mytuple_to_list(T)->[元素(1,T)| mytuple_to_list(erlang:delete_元素(1,T))。

我正在尝试乔·阿姆斯特朗的书中的练习,下面是我的想法

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

my_tuple\u to_list(tuple)->[element(T,tuple)|T奇怪的是,我现在正在使用Joe Armstrong的同一本书学习这一点。第二版和第4章是关于模块和函数的,涵盖列表理解、保护、累加器等。无论如何,使用这些知识,我的解决方案是下面的代码:

-module(my_tuple_to_list).
-export([convert/1]).

convert(T) when is_tuple(T) -> [element(Pos,T) || Pos <- lists:seq(1,tuple_size(T))].
-模块(我的元组到列表)。
-导出([convert/1])。

当元组(T)->[元素(Pos,T)时转换(T)| | Pos+1用于列表理解。我喜欢列表的用法:seq.对我来说有点像pythonian。;)让自己意识到下面的哪些实现是尾部递归的。拥有帮助函数没有什么错,通常你需要它们,它们是做事情的最佳方式。不要过度关注尾部递归,请参阅+1了解getting去掉了helper函数以及对计数器和累加器的需求。我了解到当前版本中尾部递归与头部递归的加速更多地是处理器架构的问题*因此我喜欢这个解决方案退出!*-1对于一个在列表中添加元素时创建新元组的解决方案。记住,列表中没有可变数据erlang和
erlang:delete_element/2
创建了一个新的元组!@Zakum:你应该更仔细地阅读这个神话去神秘化。最后调用
lists:reverse/1
的body递归列表函数和tail递归函数将使用完全相同的内存量请注意
lists:reverse/1
,我的版本没有做。我的尾部递归版本肯定会比身体递归版本快,这是毫无疑问的。但是当大多数元组都很小的时候,我不在乎。但是要知道区别。@r如果我理解正确的话,那是关于优雅的
tuple\u to\u list/1
不是关于最优化的,因为你无论如何都不能打败它。@hdima True,但是一个ele甘特图解决方案并非毫无必要地低效。IMAO。最好使用
元组大小/1
而不是
大小/1
。请参见此处: