Using macros to generate NamedTuples

I am a bit confused by using macros to generate expressions. I would like to have a macro to make NamedTuples as follows:

a = 1
b = 2
@make_nt a b

which should return an expression that evaluates to NamedTuple{(:a, :b)}((a, b)) or (a=1, b=2)


macro make_nt_try(args...)
    return :(NamedTuple{$args}($args))

returns (a = :a, b = :b)


macro make_nt_expr(args...)
    return Expr(:(NamedTuple{$args}), args)

raises TypeError: in Expr, expected Symbol, got Expr


macro make_nt(args...)
    return :(NamedTuple{$args}(tuple($(args...))))

works outside of functions, but not for variables in the local scope of functions.
I have read the metaprogramming section of the documentation, but did not understand when exactly evaluation happens and why it does not happen within the local scope.

@macroexpand @make_nt(a, b)

always gives

:(Main.NamedTuple{(:a, :b)}(Main.tuple(Main.a, Main.b)))

even when it is called inside a function.

Is it possible to make a macro that works properly inside function, or is my mental model for how macros should be used wrong in some way?

Looks like like you’re missing an esc. See the macro hygiene section of the documentation.

Does this do what you want?

macro make_nt(args...)
    return :(NamedTuple{$args}(tuple($(esc.(args)...))))

It does, thank you for the quick reply! I will look deeper in the escaping and macro hygiene parts to understand it.