Sorry, for the misunderstanding, I thought there was a missing chunk.
I wasn’t talking about escaping, I was talking about the difference between
:(($(args...),))
and
:(($(args...,)))
To in your code, the problem is that when you write
:(@show $vars, $expr)
this doesn’t do what you want:
julia> let vars = [:x, :y], expr=:(x && y)
:(@show $vars, $expr)
end
:(#= REPL[91]:2 =# @show ([:x, :y], x && y))
here we see there’s a vector of Symbols in here instead of what you wanted. This can be re-written as
julia> let vars = [:x, :y], expr=:(x && y)
:(@show [$(vars...)], $expr)
end
:(#= REPL[92]:2 =# @show ([x, y], x && y))
to now get a vector of x and y. Though, for efficiency, you likely are better off writing
julia> let vars = [:x, :y], expr=:(x && y)
:(@show ($(vars...),), $expr)
end
:(#= REPL[93]:2 =# @show ((x, y), x && y))
to get a Tuple of values instead.
Here’s the revised macro:
julia> macro truth_table(expr)
# Walk the expression and push the variables found to a vector `vars`:
vars = Vector{Symbol}() # the `[]` wasn't necessary here.
find_vars!(var::Symbol) = !(var in vars) && push!(vars, var)
find_vars!(expr::Expr) = find_vars!.(expr.args)
find_vars!(::Bool) = nothing
find_vars!(expr)
# Generate nested for loops where each variable is given a truth value:
ex = :(@show ($(vars...),), $expr)
for i in reverse(vars) # Take a variable (in the order they were found).
ex = quote
for $i in (true, false) # Iterate over truth values.
$ex # Nest the previous expression.
end
end
end
return ex
end # truth_table
@truth_table (macro with 1 method)
Now, we have
julia> @truth_table x && y
((x, y), x && y) = ((true, true), true)
((x, y), x && y) = ((true, false), false)
((x, y), x && y) = ((false, true), false)
((x, y), x && y) = ((false, false), false)
and
julia> @truth_table p || (q && r)
((p, q, r), p || q && r) = ((true, true, true), true)
((p, q, r), p || q && r) = ((true, true, false), true)
((p, q, r), p || q && r) = ((true, false, true), true)
((p, q, r), p || q && r) = ((true, false, false), true)
((p, q, r), p || q && r) = ((false, true, true), true)
((p, q, r), p || q && r) = ((false, true, false), false)
((p, q, r), p || q && r) = ((false, false, true), false)
((p, q, r), p || q && r) = ((false, false, false), false)