跳转到内容

Erlang 编程/列表推导

来自维基教科书,开放世界中的开放书籍

列表推导

[编辑 | 编辑源代码]

推导介绍

[编辑 | 编辑源代码]

列表推导是一种数学方法,用于构造列表。要进行列表推导,我们必须使用一个新的运算符“<-”,“取自”。

L = [ X*X || X <- [1,2,3,4] ].

英文翻译是:构建一个列表 L,其元素的值为 X*X,条件是 X 取自列表 [1,2,3,4]。它输出

[1,4,9,16]

请注意,这类似于

lists:map(fun(X) -> X*X end, [1,2,3,4])

事实上,列表推导为 lists 模块中的大多数函数提供了一种简写表示法。

简单推导

[编辑 | 编辑源代码]

您可以使用它们来求解方程。

 L = [ {X,Y} || X <- [1,2,3,4], Y <- [1,2,3,4], X*X == Y].

输出

[ {1,1}, {2,4} ]

列表版本

[编辑 | 编辑源代码]

你能弄清楚上面推导中使用的列表函数吗?

怎么样

 F = fun(X, Y) ->
  lists:filter(fun({X0, Y0}) -> X0 * X0 == Y0 end,
     lists:reverse(
        lists:foldl(fun(E, Acc) -> 
             lists:zip(lists:duplicate(length(Y), E), Y) ++ Acc
           end, [], X))) end.
 F([1,2,3,4], [1,2,3,4]).

那是 5 个函数在一个简洁的行中。对于剩余的示例,花一些时间找到执行相同操作的相应列表函数。

这里我们掷两枚硬币

[ [X]++[Y] || X<-"HT", Y<-"HT"].

注意:在 erlang 中,字符串是列表。所有组合是:输出

["HH","HT","TH","TT"]

中级列表推导

[编辑 | 编辑源代码]

列表推导的一个重要用途是帮助将 Prolog 式语句翻译成 Erlang。[为什么这很重要?]

1- Erlang 是一种面向函数的语言,专为消息传递(MIMD)并行处理而设计。Prolog 专为逻辑编程而设计。有时,问题最容易被定义为对某些数据集的一组逻辑约束。如果有人从逻辑上思考或从约束上思考,或者从 prolog 上思考,这种列表推导风格可以是你在 erlang 中完成任务的有效方法。在 prolog 中存在许多有用的解决方案,可以通过列表推导迁移到 erlang。

2- 约束编程和逻辑编程被认为是比函数更高级的编程方式,因此,它们是节省时间并提高简洁性的好方法。

警告:基于约束和逻辑的程序可能更难调试,因为严格的逐步操作被隐藏并委托给列表推导引擎。erlang 列表推导中约束的顺序会影响输出。约束的顺序依赖性可能是非直观的干扰。

注意:一般来说,使用大量原子并不是一个好主意,因为它们永远不会被垃圾回收。

-module(think).              %
-compile(export_all).        %
                             %
male(adam) -> true;          %
male(seth) -> true;
male(cain) -> true;
male(abel) -> true;
male(noah) -> true;
male(_X) -> false.
                             %
female(eve) -> true;
female(_X) -> false.
                             %
parent(adam,cain) -> true;
parent(adam,abel) -> true;
parent(eve,cain) -> true;
parent(eve,abel) -> true;
parent(noah,shem) -> true;
parent(_X,_Y) -> false.
                                                %
people() ->
       [ adam, shem, cain, abel, eve, noah ].
                                                %
father_of() ->
       [ {X,Y} || X <- people(), Y <- people(), parent(X,Y), male(X) ].
mother_of() ->
       [ {X,Y} || X <- people(), Y <- people(), parent(X,Y), female(X) ].

使用 c(think) 编译并使用以下命令生成输出

17> think:father_of() ++ think:mother_of().
[{adam,cain},{adam,abel},{noah,shem},{eve,cain},{eve,abel}]

高级列表推导

[编辑 | 编辑源代码]

带 7 行代码的快速排序示例。

-module(sort).
-compile(export_all).
                                % classic way to show off erlang terseness.
qsort([]) ->
   [];
qsort([H | T]) -> 
   qsort([ X || X <- T, X < H ]) ++ [H] ++ qsort([ X || X <- T, X >= H ]).
% sample output:
%
% sort:qsort([1,5,3,7,6,8,9,4]).
%   [1,3,4,5,6,7,8,9]

(顺便说一句:这实际上不是“快速排序”,因为你想使用它,因为它使用比必要更多的内存,并且没有获得就地快速排序的 VM 页面/缓存优势。但它仍然很酷!)

1) 使用列表推导编写一个程序,找到半径为 5 的圆的整数解 {X,Y}。

1)

-module( solve_circle).
-export( [start/0] ).
                                                  %
numbers() -> lists:seq(-5,5).
                                                  %
start() -> [ {X,Y} ||
                   X <- numbers(),
                   Y <- numbers(),
                   X*X + Y*Y == 25 ].
                                                   %
% ================================================ %
% sample output
% 11> solve_circle:start().
% [{-5,0}, {-4,-3}, {-4,3}, {-3,-4}, 
%  {-3,4}, {0,-5}, {0,5}, {3,-4},
%  {3,4}, {4,-3}, {4,3}, {5,0}]
华夏公益教科书