代码之家  ›  专栏  ›  技术社区  ›  Aleksei Matiushkin

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

  •  5
  • Aleksei Matiushkin  · 技术社区  · 6 年前

    请考虑以下代码:

    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) .

    为什么连续减法列表会导致noop?


    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 回复  |  直到 6 年前
        1
  •  5
  •   Máté    6 年前

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

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

    实际评估为

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

    当您获取括号中的内容时:从中删除元素列表 [:foo] ,删除的列表包含原始列表( [Fo] )因此计算为空列表 [] .

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

    [:foo, :bar] -- []
    

    这就给你留下了结果 [:foo, :bar] .

        2
  •  0
  •   jkmrto    6 年前

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

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

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

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

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

    所以结尾处会有一个空列表。