如何在宏执行之前将变量传递给宏并对其求值?

时间:2018-11-23 02:56:24

标签: julia

如果我有方法

macro doarray(arr)
    if in(:head, fieldnames(typeof(arr))) && arr.head == :vect
        println("A Vector")
    else
        throw(ArgumentError("$(arr) should be a vector"))
    end
end

如果我写这个的话就可以了

@doarray([x])

@doarray([:x])

,但以下代码正确地行不通,从而提高了ArgumentError(即ArgumentError: alist should be a vector)。

alist = [:x]
@doarray(alist)

如何使上述内容与@doarray([x])相似

动机: 我有一个递归宏(例如mymacro),它使用一个向量,对第一个值进行运算,然后用向量的其余部分(例如mymacro)递归调用rest_vector。我可以创建rest_vector,正确打印值(用于调试),但是当我再次将其馈送到rest_vector时,我不知道如何求值mymacro

编辑1: 我正在尝试在Julia中实现logic programming,即MiniKanren。在我以此为基础的Clojure实现中,代码就是这样。

(defmacro fresh
  [var-vec & clauses]
  (if (empty? var-vec)
    `(lconj+ ~@clauses)
    `(call-fresh (fn [~(first var-vec)]
                   (fresh [~@(rest var-vec)]
                     ~@clauses)))))

基于此的我失败的Julia代码如下。如果这没有意义,我深表歉意,因为我正在尝试通过实现宏来理解宏。

macro fresh(varvec, clauses...)
    if isempty(varvec.args)
        :(lconjplus($(esc(clauses))))
    else
        varvecrest = varvec.args[2:end]
        return quote
            fn = $(esc(varvec.args[1])) -> @fresh($(varvecvest), $(esc(clauses)))
            callfresh(fn)
        end
    end
end

运行代码@fresh([x, y], ===(x, 42))时遇到的错误(在此讨论中,您可以忽略===(x, 42)

ERROR: LoadError: LoadError: UndefVarError: varvecvest not defined

问题行为fn = $(esc(varvec.args[1])) -> @fresh($(varvecvest), $(esc(clauses)))

1 个答案:

答案 0 :(得分:1)

如果我正确理解了您的问题,最好在宏内调用一个函数(而不是宏),该函数将对传递给该宏的AST进行操作。这是一个简单的示例,您如何做到:

function recarray(arr)
    println("head: ", popfirst!(arr.args))
    isempty(arr.args) || recarray(arr)
end

macro doarray(arr)
    if in(:head, fieldnames(typeof(arr))) && arr.head == :vect
        println("A Vector")
        recarray(arr)
    else
        throw(ArgumentError("$(arr) should be a vector"))
    end
end

当然,在此示例中,我们没有做任何有用的事情。如果您确切说明了要实现的目标,那么我可能会建议更具体的内容。