I use a domain specific language which has a preprocessor that's reminiscent of a C/C++ preprocessor but with differences, I hope it's self explanatory to show some examples, if not I can detail the specs.
#define VAL value
#macro MACRONAME($var1,$var2) ( ($var1) + ($var2))
The \ character permits to have a replacement or macro text that contains a newline. e.g.
#define VAL $var=1\
$var=2
will preprocess VAL into
$var=1
$var=2
Roughly I'm trying to generate the following
ADD 1 "SNA"
ADD 2 "FOO"
ADD 3 "BAR"
SHOW
$var_sna ASSIGN 1
$var_foo ASSIGN 2
$var_bar ASSIGN 3
basically SHOW uses the titles, shows a UI, gets back user input, then assign the fetched user input to the variables.
The problem would be that it's error prone, if you don't triple check the indices this will bite you in the ass and not assign the value you think to the variable you think, and you'll destroy your sample.
I managed to get something that looks like (this preprocessor permits nested evaluation)
#macro MACROADD($index,$variable,$title,$inside) ADD $index $title\
$inside\
$variable ASSIGN
which permits me to write
MACROADD(1,$var_bar,"BAR",MACROADD(2,$var_foo,"FOO",MACROADD(3,$var_sna,"SNA","SHOW")))
which expands to what I want. But it's really ugly, and will probably break when the length of the line goes to large values (ideally I'd like to be able to add as many variables as I want, within reasons ofc. Is there any tricks I'm missing?
I kind of solved it by making my surrounding functions idempotent (I don't care if I "assign" before show or "add" after show) and accessing a global counter. Basically, this
ADD 1 "SNA"
$var_sna ASSIGN 1
ADD 2 "FOO"
$var_foo ASSIGN 2
ADD 3 "BAR"
$var_bar ASSIGN 3
SHOW
ADD 1 "SNA"
$var_sna ASSIGN 1
ADD 2 "FOO"
$var_foo ASSIGN 2
ADD 3 "BAR"
$var_bar ASSIGN 3
works as well. To generate the indices I can access a global variable and add 1 at each "ADD ASSIGN"
#macro ADDASSIGN($variable,$title) ADD $title\
$variable ASSIGN $glob\
$glob=$glob+1
#macro STACK($inside,$element) $glob=1\
$element\
$inside\
$glob=1
$element
Then, I put the definition of the different steps in a define, therefore I can write:
#define RUN\
ADDASSIGN($var_sna,"HELLO THIS IS SNA")\
ADDASSIGN($var_foo,"HELLO FOO SPEAKING")\
ADDASSIGN($var_bar,"Meh, I AM BAR")\
STACK(SHOW,RUN)
and the preprocessor will generate the correct source code, and the original code contains the definitions in only one place, great success.
Related
I'm just getting my feet wet in R and was surprised to see that a function doesn't modify an object, at least it seems that's the default. For example, I wrote a function just to stick an asterisk on one label in a table; it works inside the function but the table itself is not changed. (I'm coming mainly from Ruby)
So, what is the normal, accepted way to use functions to change objects in R? How would I add an asterisk to the table title?
Replace the whole object: myTable = title.asterisk(myTable)
Use a work-around to call by reference (as described, for example, in Call by reference in R by TszKin Julian?
Use some structure other than a function? An object method?
The reason you're having trouble is the fact that you are passing the object into the local namespace of the function. This is one of the great / terrible things about R: it allows implicit variable declarations and then implements supercedence as the namespaces become deeper.
This is affecting you because a function creates a new namespace within the current namespace. The object 'myTable' was, I assume, originally created in the global namespace, but when it is passed into the function 'title.asterisk' a new function-local namespace now has an object with the same properties. This works like so:
title.asterisk <- function(myTable){ do some stuff to 'myTable' }
In this case, the function 'title.asterisk' does not make any changes to the global object 'myTable'. Instead, a local object is created with the same name, so the local object supercedes the global object. If we call the function title.asterisk(myTable) in this way, the function makes changes only to the local variable.
There are two direct ways to modify the global object (and many indirect ways).
Option 1: The first, as you mention, is to have the function return the object and overwrite the global object, like so:
title.asterisk <- function(myTable){
do some stuff to 'myTable'
return(myTable)
}
myTable <- title.asterisk(myTable)
This is okay, but you are still making your code a little difficult to understand, since there are really two different 'myTable' objects, one global and one local to the function. A lot of coders clear this up by adding a period '.' in front of variable arguments, like so:
title.asterisk <- function(.myTable){
do some stuff to '.myTable'
return(.myTable)
}
myTable <- title.asterisk(myTable)
Okay, now we have a visual cue that the two variables are different. This is good, because we don't want to rely on invisible things like namespace supercedence when we're trying to debug our code later. It just makes things harder than they have to be.
Option 2: You could just modify the object from within the function. This is the better option when you want to do destructive edits to an object and don't want memory inflation. If you are doing destructive edits, you don't need to save an original copy. Also, if your object is suitably large, you don't want to be copying it when you don't have to. To make edits to a global namespace object, simply don't pass it into or declare it from within the function.
title.asterisk <- function(){ do some stuff to 'myTable' }
Now we are making direct edits to the object 'myTable' from within the function. The fact that we aren't passing the object makes our function look to higher levels of namespace to try and resolve the variable name. Lo, and behold, it finds a 'myTable' object higher up! The code in the function makes the changes to the object.
A note to consider: I hate debugging. I mean I really hate debugging. This means a few things for me in R:
I wrap almost everything in a function. As I write my code, as soon as I get a piece working, I wrap it in a function and set it aside. I make heavy use of the '.' prefix for all my function arguments and use no prefix for anything that is native to the namespace it exists in.
I try not to modify global objects from within functions. I don't like where this leads. If an object needs to be modified, I modify it from within the function that declared it. This often means I have layers of functions calling functions, but it makes my work both modular and easy to understand.
I comment all of my code, explaining what each line or block is intended to do. It may seem a bit unrelated, but I find that these three things go together for me. Once you start wrapping coding in functions, you will find yourself wanting to reuse more of your old code. That's where good commenting comes in. For me, it's a necessary piece.
The two paradigms are replacing the whole object, as you indicate, or writing 'replacement' functions such as
`updt<-` <- function(x, ..., value) {
## x is the object to be manipulated, value the object to be assigned
x$lbl <- paste0(x$lbl, value)
x
}
with
> d <- data.frame(x=1:5, lbl=letters[1:5])
> d
x lbl
1 1 a
2 2 b
3 3 c
> updt(d) <- "*"
> d
x lbl
1 1 a*
2 2 b*
3 3 c*
This is the behavior of, for instance, $<- -- in-place update the element accessed by $. Here is a related question. One could think of replacement functions as syntactic sugar for
updt1 <- function(x, ..., value) {
x$lbl <- paste0(x$lbl, value)
x
}
d <- updt1(d, value="*")
but the label 'syntactic sugar' doesn't really do justice, in my mind, to the central paradigm that is involved. It is enabling convenient in-place updates, which is different from the copy-on-change illusion that R usually maintains, and it is really the 'R' way of updating objects (rather than using ?ReferenceClasses, for instance, which have more of the feel of other languages but will surprise R users expecting copy-on-change semantics).
For anybody in the future looking for a simple way (do not know if it is the more appropriate one) to get this solved:
Inside the function create the object to temporally save the modified version of the one you want to change. Use deparse(substitute()) to get the name of the variable that has been passed to the function argument and then use assign() to overwrite your object. You will need to use envir = parent.frame() inside assign() to let your object be defined in the environment outside the function.
(MyTable <- 1:10)
[1] 1 2 3 4 5 6 7 8 9 10
title.asterisk <- function(table) {
tmp.table <- paste0(table, "*")
name <- deparse(substitute(table))
assign(name, tmp.table, envir = parent.frame())
}
(title.asterisk(MyTable))
[1] "1*" "2*" "3*" "4*" "5*" "6*" "7*" "8*" "9*" "10*"
Using parentheses when defining an object is a little more efficient (and to me, better looking) than defining then printing.
Okay this might get a tad complex or not.
Have a file with a multivalues in attribute 4
I want to write another dictionary item that loops through the multivalue list, calls a subroutine and returns calculated values for each item in attribute 4.
somthing like
<4> a]b]c]d]e
New attribute
#RECORD<4>;SUBR("SUB.CALC.AMT", #1)
Result
<4> AMT
a 5.00
b 15.00
c 13.50
d 3.25
Not quite sure how to pass in the values from RECORD<4>, had a vague notion of a #CNT system variable, but that's not working, which might mean it was from SB+ or one of the other 4GLs.
You might be over thinking this.
You should just be able to reference it without out doing the ";" and #1 thing (I am not familiar with that convention). Using an I-Descriptor this should do the trick, though I have traditionally used the actual dictionary names instead of the #RECORD thing.
SUBR("SUB.CALC.AMT", #RECORD<4>)
This should work provided your subroutine is compiled, cataloged and returns your desired value with the same value/subvalue structure as #RECORD<4> in the first parameter of the Subroutine.
SUBROUTINE SUB.CALC.AMT(RETURN.VALUE,JUICY.BITS)
JBC = DCOUNT(JUICY.BITS<1>,#VM)
FOR X=1 TO JBC
RETURN.VALUE<1,X> = JUICY.BITS<1,X>:" or something else"
NEXT X
RETURN
END
Good luck.
If I want to know, whether variable v exists in zsh, I can use ${+v}. Example:
u=xxx
v=
print ${+u} ${+v} ${+w}
outputs 1 1 0.
If I want to access the content of a variable, where I have the NAME of it stored in variable v, I can do it with ${(P)v}. Example:
a=xxx
b=a
print ${(P)b}
outputs xxx.
Now I would like to combine the two: Testing whether a variable exists, but the name of the variable is stored in another variable. How can I do this? Example:
r=XXX
p=r
q=s
Here is my approach which does NOT work:
print ${+${(P)p}} # Expect 1, because $p is r and r exists.
print ${+${(P)q}} # Expect 0, because $q is s and s does not exist
However, I get the error message zsh: bad substitution.
Is there a way I can achieve my goal without reverting to eval?
print ${(P)+p}
print ${(P)+q}
The opening parenthesis of of a Parameter Expansion Flag needs to follow immediately after the opening brace. Also, it is not necessary to explicitly substitute p or q as (P) takes care of that. Nevertheless, ${(P)+${p}} and ${(P)+${q}} would also work.
I have defined a global variable global x=-2. Once created, global variables cannot be reassigned, i.e., x=7 will not change the -2 value of x. For this reason I clear the variable.
>> clear x
I check that the variable does not exist any more.
>> exist("x")
ans = 0
But when I create the global variable again with a new value, for example, global x=7 I get the global variable in the old value.
>> global x=7
>> x
x = -2
Why is this happening? Is the variable x not really deleted?
What you see is expected behaviour. It looks weird but consider the following example:
global x = 5;
function say_x ()
global x = 3;
disp (x);
endfunction
say_x ();
x = 7;
say_x ();
Which returns:
5
7
Note that you need declare x within functions to access the global variable. Also note that assigning to it the value of 3 does not work. The reason is that lines such as persistent x = 3 or global x = 3 are only evaluated the first time. This means that when you call say_x(), x already has a value so it never assigns to it the value of 3 (the right hand side never even gets evaluated).
Now; on to your actual issue which is all of this happening in the main/base namespace/symbol table, mixed up with what clear() is supposed to do. You are running this:
global x = 1;
clear x;
global x = 2;
x # you are surprised that x is 1 instead of 2
First, note that clear() does not actually clears the values of the variables. It will remove their names from the symbol table. Note the help text from clear():
-- Command: clear [options] pattern ...
Delete the names matching the given patterns from the symbol table.
With "normal" variables, the names won't be anywhere else and you will effectively remove their value. But that's not true with global variables. Their values will remain somewhere, ready to be made accessible the next time a global variable with their name gets defined.
What is happening when you try to define x again, is that the name already exists in the symbol table of global variables. So you are bringing it back to the current symbol table (just like what happens inside a function) and the right hand side (= 2) never gets evaluated.
As you already found, to actually remove names from the global symbol table, you need to use clear -global (as it is documented on the help text of clear).
We need to use the option -global to effectively delete the global variable: clear -global x
Example:
>> global x=-2
>> clear -global x
>> exist("x")
ans = 0
>> global x=7
>> x
x = 7
This must be a bug in Octave, because clear command alone seems to work fine clearing the global variable: no error message, and the "exist" check outputs the expected.
(Hope it helps, it took me some minutes to find the solution ;))
i would love to have functionality like this:
print(randomParameter(1,2,3))
-- prints 1 2 or 3... randomly picks a parameter
i have tried using the func(...) argument but i cant seem to use the table ARG when i pass multiple parameters. I tried this:
function hsv(...)
return arg[math.random(1,#arg)] -- also tried: return arg[math.random(#arg)]
end
print(hsv(5,32,7))
i have even tried putting the #arg into a variable using the rand function, also making a for loop with it sequentially adding a variable to count the table. still nothing works.
i remember doing this a while back, amd it looked different then this. can anyone Help with this? THANKS!
To elaborate a bit on #EgorSkriptunoff's answer (who needs to change his habit of providing answers in comments ;)): return (select(math.random(select('#',...)),...)).
... provides access to vararg parameter in the function
select('#', ...) returns the number of parameters passed in that vararg
math.random(select('#',...)) gives you a random number between 1 and the number of passed parameters
select(math.random(select('#',...)),...) gives you the element with the index specified by that random number from the passed parameters.
The other solution that is using arg = {...} gives you almost the same result with one subtle difference related to the number of arguments when nil is included as one of the parameters:
> function f(...) print(#{...}, select('#', ...)) end
> f(1,2,3)
3 3
> f(1,2,nil)
2 3
> f(1,2,nil,3)
2 4
As you can see select('#',...) produces more accurate results (this is running LuaJIT, but as far as I remember, Lua 5.1 produces similar results).
function randomNumber(...)
t = {...}
return t[math.random(1,#t)]
end
print(randomNumber(1, 5, 2, 9))
> 1 or 5 or 2 or 9