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-lang






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 23 at 20:28

























      asked Nov 23 at 2:56









      RAbraham

      2,51222643




      2,51222643
























          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 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 at 20:27










          • will try that. Thanks Bogumil :)
            – RAbraham
            Nov 23 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 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 at 20:27










          • will try that. Thanks Bogumil :)
            – RAbraham
            Nov 23 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 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 at 20:27










          • will try that. Thanks Bogumil :)
            – RAbraham
            Nov 23 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 at 7:36









          Bogumił Kamiński

          11.9k11120




          11.9k11120












          • 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 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 at 20:27










          • will try that. Thanks Bogumil :)
            – RAbraham
            Nov 23 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 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 at 20:27










          • will try that. Thanks Bogumil :)
            – RAbraham
            Nov 23 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 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 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 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 at 20:27












          will try that. Thanks Bogumil :)
          – RAbraham
          Nov 23 at 20:29




          will try that. Thanks Bogumil :)
          – RAbraham
          Nov 23 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.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • 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







          Popular posts from this blog

          A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

          Calculate evaluation metrics using cross_val_predict sklearn

          Insert data from modal to MySQL (multiple modal on website)