跳轉到內容

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}]
華夏公益教科書