Elixir的loops,嗯.....
遞迴!是的,我們的老朋友遞迴又出現了.
來看一個簡單的範例,產生自然數的.
defmodule NaturalNums do
  def print(1), do: IO.puts(1)
  def print(n) do
    print(n - 1)
    IO.puts(n)
  end
end
編譯及執行:
iex(1)> c "natural_nums.ex"
[NaturalNums]
iex(2)> NaturalNums.print(3)
1
2
3
:ok
再來看一個加總list的範例.
defmodule ListHelper do
  def sum([]), do: 0
  def sum([head | tail]) do
    head + sum(tail)
  end
end
尾遞迴的版本:
defmodule ListHelper do
  def sum(list) do
    do_sum(0, list)
  end
  defp do_sum(current_sum, []) do
    current_sum
  end
  defp do_sum(current_sum, [head | tail]) do
    new_sum = head + current_sum
    do_sum(new_sum, tail)
  end
end
相信大家對遞迴與尾遞迴應該很熟悉了.
這在前面Erlang的部份也有介紹過.直接來看範例.
凡是可以計數的,序列化的,(enumerable);都可以使用
Enum模組裡的函數,搭配Higer-order functions
的方法再加工.
iex(1)> Enum.each(
...(1)>   [1,2,3],
...(1)>   fn(x) -> IO.puts(x) end
...(1)> )
1
2
3
:ok
iex(2)> Enum.map(
...(2)>   [1,2,3],
...(2)>   &(&1 * 2)
...(2)> )
[2, 4, 6]
iex(3)> Enum.filter(
...(3)>   [1,2,3],
...(3)>   fn(x) -> rem(x, 2) == 1 end
...(3)> )
[1, 3]
可以改寫成
iex(4)> Enum.filter(
...(4)>   [1,2,3],
...(4)>   &(rem(&1,2) == 1)
...(4)> )
[1, 3]
Enum的 Enum.each, Enum.map, Enum.filter 三個函數,
相信大家都很熟悉了.
來介紹一下Enum.reduce/3
在介紹Elixir的Enum.reduce之前,我們先來看另一種程式
語言的片段:
var sum = 0;
[1,2,3].forEach(function(element) {
  sum += element;
})
這程式語言有受到Lisp影響.有看出來是哪個程式語言了嗎?
現在回到Elixir,介紹Enum.reduce的格式:
Enum.reduce(
    enumerable,
    initial_acc,
    fn(element, acc) ->
      ...
    end
)
對 list [1,2,3]進行加總,可以這樣寫
iex(5)> Enum.reduce(
...(5)>   [1,2,3],
...(5)>   0,
...(5)>   fn(element, sum) -> sum + element end
...(5)> )
6
上面的fn 可以改寫成lambda方式.
iex(6)> Enum.reduce([1,2,3], 0, &+/2)
6
結合上面介紹的Enum.reduce及lambda方式,
可以將加總寫成以下形式.
defmodule NumHelper do
  def sum_nums(enumberable) do
    Enum.reduce(enumberable, 0, &add_num/2)
  end
  defp add_num(num, sum) when is_number(num), do: sum + num
  defp add_num(_, sum), do: sum
  
end
實際應用:
iex(8)> NumHelper.sum_nums([1,"Hi", :xyz, 2, 3, "World"])
6
這在前面Erlang的部份,也有介紹過.直接看範例.
iex(9)> for x <- [1,2,3] do
...(9)>   x * x
...(9)> end
[1, 4, 9]
你沒看錯,有for
Elixir有for,用在 List Comprehension,看上面的範例,就與一般程式語言
的方式差別不大了.
Erlang的List Comprehension格式偏向數學式,Elixir偏向一般方式.
例如在數學中,我們要表達正整數可以用以下方式

在Erlang 中
[ x || x <- ListofIntegers, x > 0]

來看應用範例,假設阿拉蕾,多拉A夢跟哥吉拉要一起聚餐,
但是飯店房門無法讓超過2m的通過,可以使用以下程式,
看誰到室內用餐.
customers = [
  %{ name: "arale",    height: 1.39},
  %{ name: "doraemon", height: 1.293},
  %{ name: "godzilla", height: 150}
]
for data = %{ height: howtall} <- customers
  howtall < 2
  do: IO.inspect data
結果是:
%{height: 1.39, name: "arale"}
%{height: 1.293, name: "doraemon"}
哥吉拉只能在室外用餐了.