管道地图试图调用原始功能

时间:2014-03-23 12:49:16

标签: elixir

以下代码应该读取文件并为每行创建Item记录:

defmodule Ship do
  defrecord Item, product_code: 0, quantity: 0, destination: ""

  def load_data do
    File.read!("data") 
      |> String.split 
      |> Enum.map &(String.split &1, ",")
      |> Enum.map &(list_to_item &1)
  end

defp list_to_item([pc, q, d | []]) do
    {parsed_q, _} = Integer.parse q
    Item.new product_code: pc, quantity: parsed_q, destination: d
  end
end

data个文件,其中包含以下内容:

1,100,London
1,30,Lisbon
3,2,Braga

问题是,当我执行load_data函数时,看起来最后一次调用Enum.map试图以递归方式调用父函数(load_data)并抛出BadArityError

输出如下:

iex(1)> Ship.load_data
** (BadArityError) #Function<0.127338698/1 in Ship.load_data/0> with arity 1 called with 2 arguments ({:cont, []}, #Function<30.103209896/2 in Enum.map/2>)
    (elixir) lib/enum.ex:2000: Enumerable.Function.reduce/3
    (elixir) lib/enum.ex:879: Enum.map/2
            ship.ex:8: Ship.load_data/0

有趣的是,如果我将load_data函数更改为:

def load_data do
  list = File.read!("data") 
    |> String.split 
    |> Enum.map &(String.split &1, ",")

  Enum.map list, &(list_to_item &1)
end

按预期工作:

iex(2)> Ship.load_data
[Ship.Item[product_code: "1", quantity: 100, destination: "London"],
 Ship.Item[product_code: "1", quantity: 30, destination: "Lisbon"],
 Ship.Item[product_code: "3", quantity: 2, destination: "Braga"]]

那么,关于错误在哪里的任何想法来自第一个版本? Aren他们应该是同等的吗?

顺便说一下,我使用的是Elixir 0.12.4。

1 个答案:

答案 0 :(得分:5)

您的代码实际上与此相同:

File.read!("data") 
|> String.split 
|> Enum.map (&(String.split &1, ",") |> Enum.map &(list_to_item &1))

您需要更多括号,因为|>的优先级高于无括号函数应用程序:

File.read!("data") 
|> String.split 
|> Enum.map(&(String.split &1, ","))
|> Enum.map(&(list_to_item &1))

这是Elixir设计中的一个不幸的缺陷(也是我仍然喜欢Erlang的唯一原因)。