The purpose of the function below is to return a string having inserted the argument value between two stars.
star-name: func [name /local stars] [
stars: "**"
insert next stars name
stars
]
print star-name "test" ;*test*
print star-name "this" ;*thistest*, but what I really want is *this*
The second time I call the function, the argument of the first call still remains inserted. I know the answer is to use copy "**".
My question is, doesn't it reassign the stars variable to "**" every time the function is called?
In the case of the function there is just one "**" string definition. That definition is used by Rebol load function just once, since load is run just once to translate the code to Rebol internal form - a block. It is true that the assignment occurs twice if you call the function twice, but the assignment does not create anything, it just makes the variable refer to the same string again.
In your comment you should notice that you actually have two "**" string definitions leading to two strings being created by load. If you use
code: [stars: "**" insert next stars something]
something: "this"
do code
something: "that"
do code
you will notice that there is just one string definition and while you do not have any function the behaviour is the same as it was when a function was used.
If you use a set-word on a series, then the default behavior is to allocate the memory for that series just the once. This allows you to use that as a static variable that persists between function calls as you have found.
If you don't want that behavior, then you need to explicitly copy the series to create a new series each time.
This is another way you can do this as the stars local is not required
star-name: func [ name ][
rejoin [ "*" name "*" ]
]
Related
X=123
Y=321
TAB1={}
z=1
for n in pairs(_ENV) do
TAB1[z] = n
z=z+1
end
-- did some more steps that removes general _ENV and only left with my script global variables
TAB2={x, y}
print(TAB2[1])
what I want is "123" but I'm getting "x"
I've tried gmatch, gsub, tostring, but I still can't get it to print the value of x (123). it's only printing "x"
**sorry I don't know how to work this text box correctly for my question
Ive tried gmatch, gsub, tostring, but I still can't get it to print the value of x (123). it's only printing "x"
These functions are for string manipulation so I don't see how they'd be useful here. The reason for the lack of "value" is that your loop is for n in pairs(_ENV) do. pairs is just a wrapper for next which returns key and value, but you're currently discarding the value. Simply add a second variable to the for name list: for name, value in pairs(_ENV) do print(value) end. Alternatively, index _ENV using n: print(_ENV[n]) (inside the loop).
Right now, I have a MAIN sub that can take one or more string arguments. But I am using two separate parameters for MAIN to do it:
sub MAIN (
Str:D $file,
*#files,
) {
#files.prepend: $file;
# Rest of the program
}
Now I am wondering if there's a more idiomatic way to achieve this, as my current solution feels a little clunky, and not very Perly.
You could do it with a proto sub
proto sub MAIN ( $, *# ){*}
multi sub MAIN ( *#files ) {
# Rest of the program
}
or with sub-signature deparsing
sub MAIN ( *#files ($,*#) ) {
# Rest of the program
}
At the risk of "over answering" - my take on "Perly" is concise as possible without becoming obscure (perhaps I'm just replacing one subjective term with two others... :-)
If you have a "slurpy" array as the only parameter, then it will happily accept no arguments which is outside the spec you put in the comments. However, a positional parameter is compulsory by default and proto's are only necessary if you want to factor out constraints on all multi's - presumably overkill for what you want here. So, this is enough:
sub MAIN($file , *#others) {
say "Received file, $file, and #others.elems() others."
}
This is close to what mr_ron put - but why not go with the default Usage message that MAIN kindly whips up for you by examining your parameters:
$ ./f.pl
Usage:
./f.pl <file> [<others> ...]
Some might say I cheated by dropping the Str type constraint on the first parameter but it really doesn't buy you much when you're restricting to strings because numerics specified at the CLI come through as type IntStr (a kind-of hybrid type) that satisfies a Str constraint. OTOH, when constraining CLI parameters to Num or Int, Perl6 will check that you're actually putting digits there - or at least, what unicode considers digits.
If you're wanting actual filenames, you can save yourself a validation step by constraining to type IO(). Then it will only work if you name a file. And finally, putting where .r after the parameter will insist that it be readable to boot:
sub MAIN(IO() $file where .r, *#others) { ...
One short line that insists on one compulsory argument that is a filename referencing a readable file, with a varying number of other parameters and a useful Usage message auto generated if it all goes sideways...
Perhaps good enough answer here:
sub MAIN(*#a where {.elems > 0 and .all ~~ Str}) {
say "got at least 1 file name"
}
sub USAGE {
say "{$*PROGRAM-NAME}: <file-name> [ <file-name> ... ]"
}
Based on docs here:
https://docs.perl6.org/type/Signature#Constraining_Slurpy_Arguments
You can also try and use simply dynamic variables:
die "Usage: $*EXECUTABLE <file> <file2>*" if !+#*ARGS;
my #files = #*ARGS;
where #*ARGS is an array with the arguments issued into the command line
You can even use #*ARGFILES, since they are actually files
I'm having a problem running my script. I can't for the life of me figure out what the illegal character is.
I have tried putting the string concatenation on separate lines, and I get the same error. I have tried using OneDate and TwoDate instead of Date_1 and Date_2, also to no avail. I have updated AHK, which didn't solve it.
I should note that I am using both MonthCal and DateTime Gui control to get these dates, then formatting them with FormatTime. Another error I have noticed, which may provide a clue, is that no matter what dates I pick in the date controls, I get 2017-Sep-01 as the output. It's possible that no values are coming through from the controls, and the FormatTime function is using today's date because the variables it's attempting to work on are blank / don't exist.
Other than than, generally I like to be more descriptive in my questions, but in this case, I think all I can say is: "Help?"
When you use the expression assignment method := you shouldn't use %. Instead you should write Output := Output Date_1 "_to_" Date_2. When you do use % with expression assignment Autohotkey dereferences the variable and tries to treat OtherDescription--2017... as a variable name and - is not a legal character for an Autohotkey variable.
The following example will help make it more clear:
astring := "some text"
output = a
Output := %Output%STRING
MsgBox % Output
The MsgBox will show "some text". This happens because Autohotkey dereferences %Output% to "a" and then assigns to it the value of astring variable (it concatenates "a" and "STRING" and then looks for a variable called astring).
I have some problems wo use a key-value-map into Velocity.
Someone has an example of this functionality?
$myMap ={}
$myMap.put("mykey1", "myvalue")
$myMap.delete("mykey1")
$myMap.getValue("mykey1")
As Nathan said, you should use:
#set ($myMap = {})
to create a new map and assign it to a variable.
Now, why is the put call printed.
Anything that is not inside a directive, like #set(not printed) or #if(not printed) or #foreach(again not printed), is printed, including free text, variables, and method calls.
Velocity can't distinguish between the different semantics of $myMap.get('mykey') and $myMap.put('key', 'value') (reader vs. writer), so the result of the put call is printed, just like any other method.
Whenever something can't be properly evaluated, because a variable is not defined or somewhere along the line a method returns null, the code that failed to be evaluated is dumped literally into the output.
As the documentation of the put method states, the function returns the previous value stored for that key, or null if no value was set at all.
Summing it all up, it's normal to get that line printed.
To try this theory out, you can do this:
#set ($myMap = {})
$myMap.put('key', 'first value')
$myMap.put('key', 'second value')
$myMap.get('key')
This will be printed:
$myMap.put('key', 'first value')
first value
second value
There are two things you can do so that the line isn't printed:
Store the outcome of the function in a temporary variable: #set ($discard = $myMap.put('key', 'value')
Use the silent method call: $!myMap.put('key', 'value')
I'd recommend the first one, since the second one will still print something when you're replacing an existing value.
Did you try doing:
#set( $myMap = {} )
Also, make sure you are using a modern version of Velocity. Ancient ones did not have map syntax in VTL.
Just add ! to not print put:
$!myMap.put('key', 'second value')
http://www.rebol.org/ml-display-thread.r?m=rmlJNWS
Graham wrote:
Can a function have a variable number of arguments?
No. But you can simulate it, by using 'any-type! function specifiers and passing unset! as arguments. Better is to use refinements.
Rebol's default dialect (the do dialect) does not support the notion of a call to a function having a variable number of arguments. If you want to break a rule as fundamental as this, then you need your own dialect. Nothing stopping you from making:
tweet [Hello World How Are You Today?]
But the idea of using word! instead of string! in this case is a little dodgy, as many common tweets aren't valid for the Rebol parser:
tweet [LOL! :)]
Neglecting that issue, note that by default you won't get any expression evaluation. So this tweet dialect would have to choose a way to show where you want an evaluation. You might use get-word elements to do variable substitution, and parentheses for more general evaluations:
>> a: 10
>> b: 20
>> tweet [When you add :a and :b you get (a + b), LOL ":)"]
"When you add 10 and 20 you get 30, LOL :)"
BTW, take-n in Rowland's example isn't returning a block. Not directly, I mean. It's perhaps better understood with parentheses, and by addressing the implicit "do" that's there on every interpretation:
do [do (take-n 4) 1 2 3 4]
take-n works with only one parameter (the "n") and then returns a function which takes n parameters. Let's call that function f, so step one of this evaluation turns into something equivalent to:
do [f 1 2 3 4]
When the second do kicks in, that function gets run...and it's returning a block. In practice, I doubt you're going to want to be counting the parameters like this.
The answer on that page is:
yes, a function can have a variable number of arguments. Do is such a function, as e.g. in:
take-n: func [n /local spec] [
spec: copy []
for i 1 n 1 [
append spec to word! append copy "a" to string! i
]
func spec reduce [:reduce append reduce [to lit-word! append copy "take" to string! n] spec]
]
do take-n 4 1 2 3 4
== [take4 1 2 3 4]