Elixir:使用`:into`作为范围生成器(数字)

时间:2017-05-11 07:35:14

标签: elixir

让我们在Elixir中看到以下表达式:

iex> for n <- 1..30, rem(n, 3) == 0, do: n * 10
[30, 60, 90, 120, 150, 180, 210, 240, 270, 300]

我尝试使用:into optional来总结它们,但它失败了:

# expect to get `1650` from `[30, 60, 90, 120, 150, 180, 210, 240, 270, 300]`
iex> for n <- 1..30, rem(n, 3) == 0, into: 0, do: n * 10
** (Protocol.UndefinedError) protocol Collectable not implemented for 0
    (elixir) lib/collectable.ex:1: Collectable.impl_for!/1
    (elixir) lib/collectable.ex:46: Collectable.into/1

是否可以使用:into来合并枚举数字值的结果?

如果是,怎么样?

2 个答案:

答案 0 :(得分:5)

不,into只能用于收集Collectable类型。整数不是Collectable

您可以在此处使用Enum.sum/1,但您可能已经知道:

iex(1)> Enum.sum(for n <- 1..30, rem(n, 3) == 0, do: n * 10)
1650

如果您的目标是不创建中间列表,可以在此使用Enum.reduce/3

Enum.reduce(1..30, 0, fn n, acc -> if(rem(n, 3) == 0, do: acc + n * 10, else: acc) end)
1650

编辑:可以使用整数Collectable来实现整数,但是我不推荐它,因为(1)这个实现是全局的,(2)没有明显的方法来“收集”变成一个整数,你也可以使用乘法而不是加法。仅出于学习目的,以下是如何为具有附加行为的整数实现Collectable

defimpl Collectable, for: Integer do
  def into(acc) do
    {acc, fn
      acc, {:cont, x} -> acc + x
      acc, _ -> acc
    end}
  end
end

IO.inspect for n <- 1..30, rem(n, 3) == 0, into: 0, do: n * 10

输出:

1650

答案 1 :(得分:1)

正如Dogbert所写,整数并没有实现Collectable协议。 如果您有任务:&#34;将列表转换为数字&#34;,请考虑Enum.reduce

a = for n <- 1..30, rem(n, 3) == 0, do: n * 10
Enum.reduce a, 0, &Kernel.+/2
> 1650