Dynamically generate function body that references args

macros
#1

This is a drastically simplified example of what I’m trying to do:

defmodule X do
  def call(val) do
    IO.inspect val
  end
end

defmodule Y do
  the_call = quote do: X.call(val)
  
  def call_it(val) do
    unquote(the_call)
  end
end

The problem is, I can’t figure out how to get the val from the quoted block to reference the argument to the call_it function. When I run this code in iex, the result is:

# Refers to `val` in function body
warning: variable "val" does not exist and is being expanded to "val()", please use parentheses to remove the ambiguity or change the variable name
  iex

# Refers to `val` argument in function head
warning: variable "val" is unused (if the variable is not meant to be used, prefix it with an underscore)
  iex:8

** (CompileError) iex: undefined function val/0
    (elixir) src/elixir_locals.erl:107: :elixir_locals."-ensure_no_undefined_local/3-lc$^0/1-0-"/2
    (elixir) src/elixir_locals.erl:108: anonymous fn/3 in :elixir_locals.ensure_no_undefined_local/3

What can I do?

0 Likes

#2

You’ve encountered macro hygiene; this definition of the_call will do what you’re looking for:

the_call = quote do: X.call(var!(val))
3 Likes