Search code examples
elixiranonymous-functionfirst-class-functions

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


I can write an anonymous function in the interactive shell directly like below.

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

However, if I write in an external file and run in the interactive shell, it shows a Compile Error.

My file name and directory path is lib/expense.ex

Below is my code

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

When I go into the folder path and run iex -S mix to run my Expense module, terminal shows Compilation error.
I'm wondering only I can run anonymous function directly into the interactive shell and not from external sources and compile it. I want to write my function as a first-class citizen. And if there is a way, how can I do it?


Solution

  • You cannot create "variables" like this in elixir (see EDIT 1 and Edit 2 below). The error you're seeing is normal.

    You can put your anonymous functions into named functions and call them from there which would give you the same result:

    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
    

    This way you're calling the named function which will return the anonymous function which then you pass the arguments to.

    EDIT 1

    You cannot create variables like that INSIDE modules. This works in iex because it's an interactive environment. However, the x = y syntax in invalid outside of a function in an elixir module.

    EDIT 2 Thanks to a correction from @Dogbert. You can actually create variables inside modules and out of functions, but you cannot use them inside def.