For some reason, I had to put quote...end block in the macro and ex is generated programmatically. This code works.
macro addsum_out()
quote
ex = :(x+y)
sum(eval(ex))
end
end
x = [1 1 1]
y = [2 2 2]
z2 = #addsum_out
When the macro is put inside a module, it no longer works:
module MyModule
export #addsum
macro addsum()
quote
ex = :(x+y)
sum(eval(ex))
end
end
end
using MyModule
x = [1 1 1]
y = [2 2 2]
z = #addsum
It says:
ERROR: LoadError: UndefVarError: x not defined
I think I should put esc somewhere, to evaluate the expression ex in the main scope outside the module. What should I handle this?
The problem here is that a macro (inside a module) referencing x will look for x in that module, e.g. MyModule.x
This is part of macro hygiene.
To prevent macro hygiene from happening, you need to esc(x) -- that means it will use whatever x is in-scope at the call-site.
Your complete solution might look like:
macro addsum_out()
quote
esc(x) + esc(y)
end
end
or more concisely:
macro addsum_out()
:( esc(x) + esc(y) )
end
Note that this is slightly different from doing esc( :(x+y) ) which would be a escaping the + function also. i.e. the module containing this macro might contain an overload for +, and if you want to use this then don't escape the +, otherwise do!
There is a little discussion about this subject in a guide I put together:
https://github.com/p-i-/MetaGuideJulia/wiki#example-swap-macro-to-illustrate-esc
Related
module HW2sol
where import HW2types
ins :: Eq a => a -> Bag a -> Bag a
ins x [] = [(x,1)]
ins x (y:ys) =
if x == fst y
then (x, snd y + 1) : ys
else y : (ins x ys)
HMW2types in this code is just a file that contains all of the declarations for the bag type. I have even copied and pasted other functions from online and they get the same error. This function takes an element and adds it to a bag.
[2 of 2] Compiling HW2sol ( HMW2sol.hs, HMW2sol.o )
HMW2sol.hs:5:1: parse error on input `ins'
You may be aware of Haskell's indentation rules. Anywhere you have a block of declarations (as in a let <decls> in <expr>, or a where, etc) or a block of statements (as in a do block), or a block of patterns & branches (as in a case expression) Haskell identifies the start of each entry in the block by the following logic:
Identify the column of the first character of the first entry in the block. Call this column C.
The next line that is indented less than C indicates the end of the block (and is not part of the block).
Before the end of the block, any line that is indented exactly C characters starts a new entry in the block.
Before the end of the block, any line that is indented more than C is a continuation line of the previous entry
This logic is consistently applied to all of Haskell's "block" constructs. They all have to be aligned this way1. And it turns out that the top-level declarations in a module form an aligned block! We just don't usually bother to think of them that way because they are conventionally started at column 1 (which means it isn't possible to end the block as no line can start before the first column; people normally just put all their top-level declarations at the start of the line and indent any continuations without ever thinking about "aligning the module's main block").
However, your code does not (successfully) use this conventional layout. Because you didn't insert a linebreak after the where, the first declaration begins at column 7, not column 1!
where import HW2types
^
1234567
Your type declaration of ins begins on column 1, so by rule 2 above (1 is less than 7) this indicates the end of the module's block of definitions; the compiler has to parse ins :: Eq a => ... as something that can follow the main block in the module, instead of parsing it as a declaration in the main block. That's why you get a parse error (nothing can follow the main block).
If you start your module's main block at column 7 then all of your declarations have to be indented to column 7. This actually works:
module HW2sol
where import HW2types
ins :: Eq a => a -> Bag a -> Bag a
ins x [] = [(x,1)]
ins x (y:ys) =
if x == fst y
then (x, snd y + 1) : ys
else y : (ins x ys)
However you'll probably find it much easier to simply put a line break after the where and have import HW2types on a new line.
1 Alternatively, blocks and their entries can be explicitly delimited with braces and semicolons. But this is not usual style in Haskell.
I am learning Julia, and in particular I am trying to get a grasp of macros, so I found, amongst other things Some useful macros for Julia - Github, and in the process of deciphering them I got this behavior in the REPL :
julia> macro once_then(expr::Expr)
#assert expr.head == :while
esc(quote
$(expr.args[2]) # body of loop
$expr # loop
end)
end
#once_then (macro with 1 method)
julia> i = 0
0
julia> #once_then while i < 10
i += 1
end
ERROR: UndefVarError: i not defined
Stacktrace:
[1] macro expansion at ./REPL[34]:2 [inlined]
[2] top-level scope at ./REPL[31]:5
julia> i
1
It clearly had access to i in the first iteration of the loop, since it incremented it, but then did i become Undefed somewhere between the end of the first loop and the beginning of the second ?
From what I can see the parenthesis after esc should include everything up to the end of the loop...
I literally just copy-pasted the code into the terminal, and I get the same behavior from the #until macro found at Julia language - Until loop, so I don't think the problem would come from the code itself... is there something crucial I'm missing ?
(btw, I'm running 1.0.4, so it shouldn't be an issue of backwards compatibility...)
Your macro is fine. the problem is the scope of the variables involved. (for more information, look at this: JuliaLang - Scope of Variables
in a nutshell, the variable i in i = 0 is in a global scope, where the loop is in a local scope. in the REPL, you can add the keywork global this to make your code work:
julia> #once_then while i < 10
global i += 1
end
other option is to do all this in a function, so all variables have local scope:
function fn()
i = 0
#once_then while i < 10
i += 1
end
return i
end
I am struggling with re-assigning a variable in a loop in Julia. I have a following example:
infile = "test.txt"
feature = "----"
for ln in 1:3
println(feature)
feature = "+"
end
open(infile) do f
#if true
# println(feature)
# feature = "----"
println(feature)
for ln in 1:5 #eachline(f)
println("feature")
#fails here
println(feature)
# because of this line:
feature = "+"
end
end
It fails if I do reassignment within the loop. I see that the issue with the variable scope, and because nested scopes are involved. The reference says that the loops introduce 'soft' scope. I cannot find out from the manual what scope open expression belongs to, but seemingly it screws things up, as if I replace open with if true, things run smoothly.
Do I understand correctly that open introduces 'hard' scope and that it is the reason why re-assignment retroactively makes the variable undefined?
You should think of
open("file") do f
...
end
as
open(function (f)
...
end, "file")
that is, do introduces the same kind of hard scope as a function or -> would.
So to be able to write to feature from the function, you need to do
open(infile) do f
global feature # this means: use the global `feature`
println(feature)
for ln in 1:5
println("feature")
println(feature)
feature = "+"
end
end
Note that this is only the case in top-level (module) scope; once inside a function, there are no hard scopes.
(The for loop in this case is a red herring; regardless of the soft scope of the loop, the access to feature will be limited by the hard scope of the anonymous function introduced by do.)
I want to automatically generate some functions and export them automatically. To have some concrete example, lets say I want to build a module, which provides functions that take a signal and apply a moving average/maximum/minimum/median... to it.
The code generation already works:
for fun in (:maximum, :minimum, :median, :mean)
fname = symbol("$(fun)filter")
#eval ($fname)(signal, windowsize) = windowfilter(signal, $fun, windowsize)
end
Giving me functions
maximumfilter
minimumfilter
...
But how do I export them automatically? e.g. I would like to add some code to the above loop like
export $(fname)
and have each function exported after creation.
You could consider using a macro:
module filtersExample
macro addfilters(funs::Symbol...)
e = quote end # start out with a blank quoted expression
for fun in funs
fname = symbol("$(fun)filter") # create your function name
# this next part creates another quoted expression, which are just the 2 statements
# we want to add for this function... the export call and the function definition
# note: wrap the variable in "esc" when you want to use a value from macro scope.
# If you forget the esc, it will look for a variable named "maximumfilter" in the
# calling scope, which will probably give an error (or worse, will be totally wrong
# and reference the wrong thing)
blk = quote
export $(esc(fname))
$(esc(fname))(signal, windowsize) = windowfilter(signal, $(esc(fun)), windowsize)
end
# an "Expr" object is just a tree... do "dump(e)" or "dump(blk)" to see it
# the "args" of the blk expression are the export and method definition... we can
# just append the vector to the end of the "e" args
append!(e.args, blk.args)
end
# macros return expression objects that get evaluated in the caller's scope
e
end
windowfilter(signal, fun, windowsize) = println("called from $fun: $signal $windowsize")
# now when I write this:
#addfilters maximum minimum
# it is equivalent to writing:
# export maximumfilter
# maximumfilter(signal, windowsize) = windowfilter(signal, maximum, windowsize)
# export minimumfilter
# minimumfilter(signal, windowsize) = windowfilter(signal, minimum, windowsize)
end
when you load it, you'll see the functions are automatically exported:
julia> using filtersExample
julia> maximumfilter(1,2)
called from maximum: 1 2
julia> minimumfilter(1,2)
called from minimum: 1 2
See the manual for more info.
I'm messing around with Lua trying to create my own "scripting language".
It's actually just a string that is translated to Lua code, then executed through the use of loadstring. I'm having a problem with my string patterns. When you branch (for example, defining a variable inside of a variable declaration) it errors. For example, the following code would error:
local code = [[
define x as private: function()
define y as private: 5;
end;
]]
--defining y inside of another variable declaration, causes error
This is happening because the pattern to declare a variable first looks for the keyword 'define', and captures everything until a semicolon is found. Therefore, x would be defined as:
function()
define y as private: 5 --found a semicolon, set x to capture
I guess my question is, is it possible to ignore semicolons until the correct one is reached? Here is my code so far:
local lang = {
["define(.-)as(.-):(.-);"] = function(m1, m2, m3)
return (
m2 == "private" and " local " .. m1 .. " = " .. m3 .. " " or
m2 == "global" and " " .. m1 .. " = " .. m3 .. " " or
"ERROR IN DEFINING " .. m1
)
end,
}
function translate(code)
for pattern, replace in pairs(lang) do
code = code:gsub(pattern, replace)
end
return code
end
local code = [[
define y as private: function()
define x as private: 10;
end;
]]
loadstring(translate(code:gsub("%s*", "")))()
--remove the spaces from code, translate it to Lua code through the 'translate' function, then execute it with loadstring
The easiest solution is to to change your last capture group from
(.-) -- 0 or more lazy repetitions
to
(.*) -- 0 or more repetitions
i.e.
pattern = 'define(.-)as(.-):(.*);'
The - modifier according to PiL matches the shortest sequence.
However, as noted in my comment, I wouldn't advise writing a parser for your language using pattern matching. It will either require really complicated patterns (to prevent edge-cases) and probably be unclear to others.