内核.-- / 2怪异的行为

时间:2019-02-04 20:13:32

标签: elixir

考虑以下代码:

iex|1 ▶ [:foo, :bar] -- [:foo, :bar]
#⇒ []

到目前为止,太好了。但是:

iex|2 ▶ [:foo, :bar] -- [] -- [:foo, :bar]
#⇒ [:foo, :bar]

甚至更多,它不是从右到左:

iex|3 ▶ [:foo, :bar] -- [:foo] -- [:foo, :bar] 
#⇒ [:foo, :bar]

iex|4 ▶ IO.inspect([:foo, :bar], label: "1") --
...|4 ▶   IO.inspect([:foo], label: "2") --
...|4 ▶   IO.inspect([:foo, :bar], label: "3")
#⇒ 1: [:foo, :bar]
#  2: [:foo]
#  3: [:foo, :bar]

#⇒ [:foo, :bar]

我缺少明显的东西吗?这里发生了什么?应该没有任何魔术,因为Kernel.--/2只是委派给:erlang.--(left, right)

为什么连续减去列表会导致无操作?


FWIW,带有括号,表示一切正常:

iex|5 ▶ ([:foo, :bar] -- [:foo]) -- [:foo, :bar]
#⇒ []

更多乐趣:

iex|6 ▶ [:foo, :bar] -- [:foo] -- []  
#⇒ [:bar]
iex|7 ▶ [:foo, :bar] -- [:foo] -- [:foo]
#⇒ [:foo, :bar]
iex|8 ▶ [:foo, :bar] -- [:foo] -- [:bar]
#⇒ [:bar]

后续调查结果。简化形式的简化以某种方式遵循了右关联语义:

Enum.reduce([[:foo, :bar], [:foo], [:foo, :bar]], &Kernel.--/2)
#⇒ [:foo, :bar]

但是具有明确功能的完整格式正确的文件

Enum.reduce(
  [[:foo, :bar], [:foo], [:foo, :bar]],
  fn e, acc -> acc -- e end
)
#⇒ []

2 个答案:

答案 0 :(得分:5)

++--right-associative operations。您的初始代码:

[:foo, :bar] -- [:foo] -- [:foo, :bar]

实际评估为

[:foo, :bar] -- ([:foo] -- [:foo, :bar])

使用括号中的内容时:从[:foo]中删除了一个元素列表,并且删除的列表包含原始列表([:foo]),因此得出的值为空列表{{1} }。

然后从最左边的列表中删除此空列表:

[]

剩下的结果[:foo, :bar] -- []

答案 1 :(得分:0)

Enum.reduce([[:foo, :bar], [:foo], [:foo, :bar]], fn e, acc -> acc -- e end),您不会遇到与[:foo, :bar] -- [:foo] -- [:foo, :bar]相同的问题,这是因为您将对每个元素进行操作,而不是同时对所有元素进行操作。

由于acc将从[]开始,因此对于每个元素,您将拥有:

#1 => []-[:foo,:bar] = []

#2 => []-[:foo] = []

#3 => []-[:foo,:bar] = []

所以您最后会有一个空列表。