Elixir Operator Overloading: Defining an exclusive range using Macros

Viewed 1956

To understand the Elixir language better, I wanted to try to do operator overloading, by adding an exclusive range operator, .... An example: 1...10 would then create a range from 1 up to but excluding 10 . (e.g. 1...10 == 1..9)

So, I looked up the definition of .., because the functionality of ... would of course be very similar.

Mmy module then became:

defmodule Sequences.Ranges do

  defmacro first ... last do
    case is_float(first) or is_float(last) or
         is_atom(first) or is_atom(last) or
         is_binary(first) or is_binary(last) or
         is_list(first) or is_list(last) do
      true ->
        raise ArgumentError,
          "ranges (first...last) expect both sides to be integers, " <>
          "got: #{Macro.to_string({:"Sequences.Ranges...", [], [first, last]})}"
      false ->
        case __CALLER__.context do
          nil -> quote do: Elixir.Range.new(unquote(first), unquote(last-1))
          _   -> {:%{}, [], [__struct__: Elixir.Range, first: first, last: (last-1)]}
        end
    end
  end

end

However, upon compiling this module, I get the following error:

== Compilation error on file lib/sequences/ranges.ex ==
** (CompileError) lib/sequences/ranges.ex:6: cannot invoke local .../1 inside match
    (stdlib) lists.erl:1353: :lists.mapfoldl/3

What am I doing wrong?

1 Answers
Related