在外部 .ex 文件中编写的 Elixir 匿名函数不能 运行 与交互式 shell

Elixir's anonymous function written in external .ex file can't run with interactive shell

我可以像下面这样直接在交互中写一个匿名函数shell。

iex> total_bottles_milk = fn total -> total * 2 end  
iex> total_bottles_milk.(2)

但是,如果我在外部文件中写入并在交互式 shell 中写入 运行,它会显示编译错误。

我的文件名和目录路径是lib/expense.ex

下面是我的代码

defmodule Expense do

    total_bread_slices = fn total -> (total * 10) / 100 end
    total_bottles_milk = fn total -> total * 2 end
    total_cakes = fn total -> total * 15 end

    def total_expense(bread_slices, bottles_of_milk, cakes) do
        total_bread_slices.(bread_slices) + total_bottles_milk.(bottles_of_milk) + total_cakes.(cakes)
    end

end

当我进入文件夹路径 运行 iex -S mix 到 运行 我的 Expense 模块时,终端显示编译错误。
我想知道我只能 运行 匿名函数直接进入交互式 shell 而不是从外部来源编译它。我想将我的函数编写为第一个 class 公民。如果有办法,我该怎么做?

您不能在 elixir 中像这样创建 "variables"(请参阅下面的 EDIT 1Edit 2)。您看到的错误是正常的。

您可以将匿名函数放入命名函数中并从那里调用它们,这会得到相同的结果:

defmodule Expense do

  def total_expense(bread_slices, bottles_of_milk, cakes) do
    total_bread_slices().(bread_slices) + total_bottles_milk().(bottles_of_milk) + total_cakes().(cakes)
  end

  defp total_bread_slices, do: fn total -> (total * 10) / 100 end
  defp total_bottles_milk, do: fn total -> total * 2 end
  defp total_cakes, do: fn total -> total * 15 end
end

通过这种方式,您将调用命名函数,该函数将 return 匿名函数,然后您将参数传递给该匿名函数。

编辑 1

您不能像 INSIDE 模块那样创建变量。这在 iex 中有效,因为它是一个交互式环境。但是,x = y 语法在 elixir 模块中的函数外部无效。

编辑 2 感谢@Dogbert 的更正。您实际上可以在模块内部和函数外部创建变量,但不能在 def.

内部使用它们

感谢@Abdullah Esmail,我可以这样写我的函数

defmodule Expense do

    def total_bread_slices do
        fn total -> (total * 10) / 100 end
    end 

    def total_bottles_milk do
        fn total -> total * 2 end
    end 

    def total_cakes do
        fn total -> total * 15 end
    end 

    def total_expense(bread_slices, bottles_of_milk, no_of_cakes) do

        bread = total_bread_slices()
        milk = total_bottles_milk()
        cakes = total_cakes()

        bread.(bread_slices) + milk.(bottles_of_milk) + cakes.(no_of_cakes)
    end

end

感谢@Dogbert,如果我想将函数用作值,这是另一种方法。

首先,我定义了一个命名函数,然后使用 Elixir 的函数捕获运算符 &,我可以更轻松地使用命名函数作为值。

这样,使用&运算符捕获对函数的引用并使用=运算符绑定到变量,我可以将命名函数绑定到变量。

defmodule Expense do

    defp total_bread_slices(total) do
        (total * 10) / 100
    end 

    defp total_bottles_milk(total) do
        total * 2 
    end 

    defp total_cakes(total) do
        total * 15 
    end 

    def total_expense(bread_slices, bottles_of_milk, no_of_cakes) do

        bread = &total_bread_slices/1
        milk = &total_bottles_milk/1
        cakes = &total_cakes/1

        bread.(bread_slices) + milk.(bottles_of_milk) + cakes.(no_of_cakes)

    end

end

我在 Elixir In Action 书第二版的 运行 示例中遇到了同样的问题。为了避免在 iex 中重新输入 lambda 函数示例,我将它们保存在一个文件中。我试图在 iex 中加载它们,例如:

iex solutions/ch05.ex

但是当我调用 lambda 函数时:

a_lambda.("something")

我在 iex 中遇到编译错误。

现在我 copy/paste 从文件直接到 Iex 的 lambda 代码,它工作了。