small medium large xlarge

Dave_gnome_head_isolated_pragsmall
15 Jul 2013, 03:42
Dave Thomas (344 posts)
  • (Hard). Try adding a method definition with a guard clause to the Test module. You’ll find that the tracing now longer works.

    • Find out why
    • See if you can fix it

    (You may need to explore Kernel.def/4)

Ernie2_pragsmall
01 May 2014, 23:28
Ernie Miller (4 posts)

I struggled with this one for a half an hour or so. So:

If you need further help, here’s a function with a guard:

def add_list_with_guard(list)
when length(list) > 3 do
  Enum.reduce(list, 0, &(&1 + &2))
end

…and here is its representation before unquoted:

{:when, [line: 37],
 [{:add_list_with_guard, [line: 36], [{:list, [line: 36], nil}]},
  {:>, [line: 37], [{:length, [line: 37], [{:list, [line: 37], nil}]}, 3]}]}

Consider what the pattern matching in your macro is then considering its definition “name” and “args”. Then, consider whether or not you might be able to define a clause for the function that takes this into account.

Generic-user-small
25 Aug 2015, 16:50
Jim Kane (6 posts)

Based on Ernie’s helpful hints, I got partway there (the lack of other posts tells me I may not be the only one who did so).

Based on the dump of the function, a guard clause looks like the last element of its tuple is an array of more functions. We can assume that the head is the outer, and the tail is the list of guard functions. So, the function def ought to look something like this:

defmacro def(definition={:when, _, [outer_function | guard_functions]}, do: content) do
  quote do
    Kernel.def(unquote(outer_function)) do
    if Enum.all?(guards) do
      result = unquote(content)
      IO.puts "<== result: #{result}"
      result
    else
      IO.puts "<== guard clause failed, no result"
      nil
    end
  end
end

Before you rush to type this example in,… it does not work. Using defmacro requires you to mentally track whether you are writing a function or writing a function to write the function, and I am still working out which line I failed on (my guess is on the Enum.all/1 call). “Ceci n’est pas une pipe.”

Hopefully some other reader will find this sketch useful on top of Ernie’s initial hints. I find this part of Elixir fascinating!

  You must be logged in to comment