How do I pass a variable to a macro and evaluate it before macro execution?
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
add a comment |
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
add a comment |
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
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
julia
edited Nov 23 '18 at 20:28
RAbraham
asked Nov 23 '18 at 2:56
RAbrahamRAbraham
2,59622644
2,59622644
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
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.
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
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
add a comment |
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.
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
add a comment |
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.
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.
answered Nov 23 '18 at 7:36
Bogumił KamińskiBogumił Kamiński
14.6k21422
14.6k21422
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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