How do I pass a variable to a macro and evaluate it before macro execution?












0















If I have a method



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


it works if I write this



@doarray([x])


or



@doarray([:x])


but the following code rightly does not work, raising the ArgumentError(i.e. ArgumentError: alist should be a vector).



alist = [:x]
@doarray(alist)


How can I make the above to act similarly as @doarray([x])



Motivation:
I have a recursive macro(say mymacro) which takes a vector, operates on the first value and then calls recursively mymacro with the rest of the vector(say rest_vector). I can create rest_vector, print the value correctly(for debugging) but I don't know how to evaluate rest_vector when I feed it to the mymacro again.



EDIT 1:
I'm trying to implement logic programming in Julia, namely MiniKanren. In the Clojure implementation that I am basing this off, the code is such.



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


My failing Julia code based on that is below. I apologize if it does not make sense as I am trying to understand macros by implementing it.



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


The error I get when I run the code @fresh([x, y], ===(x, 42))(you can disregard ===(x, 42) for this discussion)



ERROR: LoadError: LoadError: UndefVarError: varvecvest not defined


The problem line is fn = $(esc(varvec.args[1])) -> @fresh($(varvecvest), $(esc(clauses)))










share|improve this question





























    0















    If I have a method



    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


    it works if I write this



    @doarray([x])


    or



    @doarray([:x])


    but the following code rightly does not work, raising the ArgumentError(i.e. ArgumentError: alist should be a vector).



    alist = [:x]
    @doarray(alist)


    How can I make the above to act similarly as @doarray([x])



    Motivation:
    I have a recursive macro(say mymacro) which takes a vector, operates on the first value and then calls recursively mymacro with the rest of the vector(say rest_vector). I can create rest_vector, print the value correctly(for debugging) but I don't know how to evaluate rest_vector when I feed it to the mymacro again.



    EDIT 1:
    I'm trying to implement logic programming in Julia, namely MiniKanren. In the Clojure implementation that I am basing this off, the code is such.



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


    My failing Julia code based on that is below. I apologize if it does not make sense as I am trying to understand macros by implementing it.



    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


    The error I get when I run the code @fresh([x, y], ===(x, 42))(you can disregard ===(x, 42) for this discussion)



    ERROR: LoadError: LoadError: UndefVarError: varvecvest not defined


    The problem line is fn = $(esc(varvec.args[1])) -> @fresh($(varvecvest), $(esc(clauses)))










    share|improve this question



























      0












      0








      0








      If I have a method



      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


      it works if I write this



      @doarray([x])


      or



      @doarray([:x])


      but the following code rightly does not work, raising the ArgumentError(i.e. ArgumentError: alist should be a vector).



      alist = [:x]
      @doarray(alist)


      How can I make the above to act similarly as @doarray([x])



      Motivation:
      I have a recursive macro(say mymacro) which takes a vector, operates on the first value and then calls recursively mymacro with the rest of the vector(say rest_vector). I can create rest_vector, print the value correctly(for debugging) but I don't know how to evaluate rest_vector when I feed it to the mymacro again.



      EDIT 1:
      I'm trying to implement logic programming in Julia, namely MiniKanren. In the Clojure implementation that I am basing this off, the code is such.



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


      My failing Julia code based on that is below. I apologize if it does not make sense as I am trying to understand macros by implementing it.



      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


      The error I get when I run the code @fresh([x, y], ===(x, 42))(you can disregard ===(x, 42) for this discussion)



      ERROR: LoadError: LoadError: UndefVarError: varvecvest not defined


      The problem line is fn = $(esc(varvec.args[1])) -> @fresh($(varvecvest), $(esc(clauses)))










      share|improve this question
















      If I have a method



      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


      it works if I write this



      @doarray([x])


      or



      @doarray([:x])


      but the following code rightly does not work, raising the ArgumentError(i.e. ArgumentError: alist should be a vector).



      alist = [:x]
      @doarray(alist)


      How can I make the above to act similarly as @doarray([x])



      Motivation:
      I have a recursive macro(say mymacro) which takes a vector, operates on the first value and then calls recursively mymacro with the rest of the vector(say rest_vector). I can create rest_vector, print the value correctly(for debugging) but I don't know how to evaluate rest_vector when I feed it to the mymacro again.



      EDIT 1:
      I'm trying to implement logic programming in Julia, namely MiniKanren. In the Clojure implementation that I am basing this off, the code is such.



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


      My failing Julia code based on that is below. I apologize if it does not make sense as I am trying to understand macros by implementing it.



      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


      The error I get when I run the code @fresh([x, y], ===(x, 42))(you can disregard ===(x, 42) for this discussion)



      ERROR: LoadError: LoadError: UndefVarError: varvecvest not defined


      The problem line is fn = $(esc(varvec.args[1])) -> @fresh($(varvecvest), $(esc(clauses)))







      julia






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 23 '18 at 20:28







      RAbraham

















      asked Nov 23 '18 at 2:56









      RAbrahamRAbraham

      2,59622644




      2,59622644
























          1 Answer
          1






          active

          oldest

          votes


















          1














          If I understand your problem correctly it is better to call a function (not a macro) inside a macro that will operate on AST passed to the macro. Here is a simple example how you could do it:



          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


          Of course in this example we do not do anything useful. If you specified what exactly you want to achieve then I might suggest something more specific.






          share|improve this answer
























          • Bogumil Kaminski. I have added EDIT 1 to give you more context(though I fear it may make it more confusing..). Thanks for trying.

            – RAbraham
            Nov 23 '18 at 20:08








          • 1





            The use case is too complex for me to work it out now. However, there are two things I can recommend from the experience: 1) try first writing a function that takes an expression and returns an expression and make sure it gives you what you want; next turn it into a macro; 2) have the input and output expressions written down and use @macroexpand macro to see if your macro produces what you want. If this does not help you I will try to have a look at your specific example in a few days.

            – Bogumił Kamiński
            Nov 23 '18 at 20:27











          • will try that. Thanks Bogumil :)

            – RAbraham
            Nov 23 '18 at 20:29











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53440146%2fhow-do-i-pass-a-variable-to-a-macro-and-evaluate-it-before-macro-execution%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          If I understand your problem correctly it is better to call a function (not a macro) inside a macro that will operate on AST passed to the macro. Here is a simple example how you could do it:



          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


          Of course in this example we do not do anything useful. If you specified what exactly you want to achieve then I might suggest something more specific.






          share|improve this answer
























          • Bogumil Kaminski. I have added EDIT 1 to give you more context(though I fear it may make it more confusing..). Thanks for trying.

            – RAbraham
            Nov 23 '18 at 20:08








          • 1





            The use case is too complex for me to work it out now. However, there are two things I can recommend from the experience: 1) try first writing a function that takes an expression and returns an expression and make sure it gives you what you want; next turn it into a macro; 2) have the input and output expressions written down and use @macroexpand macro to see if your macro produces what you want. If this does not help you I will try to have a look at your specific example in a few days.

            – Bogumił Kamiński
            Nov 23 '18 at 20:27











          • will try that. Thanks Bogumil :)

            – RAbraham
            Nov 23 '18 at 20:29
















          1














          If I understand your problem correctly it is better to call a function (not a macro) inside a macro that will operate on AST passed to the macro. Here is a simple example how you could do it:



          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


          Of course in this example we do not do anything useful. If you specified what exactly you want to achieve then I might suggest something more specific.






          share|improve this answer
























          • Bogumil Kaminski. I have added EDIT 1 to give you more context(though I fear it may make it more confusing..). Thanks for trying.

            – RAbraham
            Nov 23 '18 at 20:08








          • 1





            The use case is too complex for me to work it out now. However, there are two things I can recommend from the experience: 1) try first writing a function that takes an expression and returns an expression and make sure it gives you what you want; next turn it into a macro; 2) have the input and output expressions written down and use @macroexpand macro to see if your macro produces what you want. If this does not help you I will try to have a look at your specific example in a few days.

            – Bogumił Kamiński
            Nov 23 '18 at 20:27











          • will try that. Thanks Bogumil :)

            – RAbraham
            Nov 23 '18 at 20:29














          1












          1








          1







          If I understand your problem correctly it is better to call a function (not a macro) inside a macro that will operate on AST passed to the macro. Here is a simple example how you could do it:



          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


          Of course in this example we do not do anything useful. If you specified what exactly you want to achieve then I might suggest something more specific.






          share|improve this answer













          If I understand your problem correctly it is better to call a function (not a macro) inside a macro that will operate on AST passed to the macro. Here is a simple example how you could do it:



          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


          Of course in this example we do not do anything useful. If you specified what exactly you want to achieve then I might suggest something more specific.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 23 '18 at 7:36









          Bogumił KamińskiBogumił Kamiński

          14.9k21422




          14.9k21422













          • Bogumil Kaminski. I have added EDIT 1 to give you more context(though I fear it may make it more confusing..). Thanks for trying.

            – RAbraham
            Nov 23 '18 at 20:08








          • 1





            The use case is too complex for me to work it out now. However, there are two things I can recommend from the experience: 1) try first writing a function that takes an expression and returns an expression and make sure it gives you what you want; next turn it into a macro; 2) have the input and output expressions written down and use @macroexpand macro to see if your macro produces what you want. If this does not help you I will try to have a look at your specific example in a few days.

            – Bogumił Kamiński
            Nov 23 '18 at 20:27











          • will try that. Thanks Bogumil :)

            – RAbraham
            Nov 23 '18 at 20:29



















          • Bogumil Kaminski. I have added EDIT 1 to give you more context(though I fear it may make it more confusing..). Thanks for trying.

            – RAbraham
            Nov 23 '18 at 20:08








          • 1





            The use case is too complex for me to work it out now. However, there are two things I can recommend from the experience: 1) try first writing a function that takes an expression and returns an expression and make sure it gives you what you want; next turn it into a macro; 2) have the input and output expressions written down and use @macroexpand macro to see if your macro produces what you want. If this does not help you I will try to have a look at your specific example in a few days.

            – Bogumił Kamiński
            Nov 23 '18 at 20:27











          • will try that. Thanks Bogumil :)

            – RAbraham
            Nov 23 '18 at 20:29

















          Bogumil Kaminski. I have added EDIT 1 to give you more context(though I fear it may make it more confusing..). Thanks for trying.

          – RAbraham
          Nov 23 '18 at 20:08







          Bogumil Kaminski. I have added EDIT 1 to give you more context(though I fear it may make it more confusing..). Thanks for trying.

          – RAbraham
          Nov 23 '18 at 20:08






          1




          1





          The use case is too complex for me to work it out now. However, there are two things I can recommend from the experience: 1) try first writing a function that takes an expression and returns an expression and make sure it gives you what you want; next turn it into a macro; 2) have the input and output expressions written down and use @macroexpand macro to see if your macro produces what you want. If this does not help you I will try to have a look at your specific example in a few days.

          – Bogumił Kamiński
          Nov 23 '18 at 20:27





          The use case is too complex for me to work it out now. However, there are two things I can recommend from the experience: 1) try first writing a function that takes an expression and returns an expression and make sure it gives you what you want; next turn it into a macro; 2) have the input and output expressions written down and use @macroexpand macro to see if your macro produces what you want. If this does not help you I will try to have a look at your specific example in a few days.

          – Bogumił Kamiński
          Nov 23 '18 at 20:27













          will try that. Thanks Bogumil :)

          – RAbraham
          Nov 23 '18 at 20:29





          will try that. Thanks Bogumil :)

          – RAbraham
          Nov 23 '18 at 20:29




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53440146%2fhow-do-i-pass-a-variable-to-a-macro-and-evaluate-it-before-macro-execution%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          這個網誌中的熱門文章

          Xamarin.form Move up view when keyboard appear

          Post-Redirect-Get with Spring WebFlux and Thymeleaf

          Anylogic : not able to use stopDelay()