Tcl syntax explanation - syntax

Tcl code:
for {local i 0 } { $i < $bsLen } { incr i } {
local topb [bs rhex $bsStream 1]
local botb [bs rhex $bsStream 1]
local hexStr [strcat $hexStr $topb $botb ]
}
What are some documents that can help to explain the above syntax?

Only for and incr are standard Tcl commands in that sample. If you know C or Java or C#, you'll probably be able to guess what those do without too much difficulty; the syntax is a little different but not very.
The other commands are these, but I know not who defines them:
local — appears to be setting a local variable. What's wrong with using set? I don't know…
bs — specifically bs rhex, and it appears to be getting a value (in hex?) from a stream (named in the bsStream variable). This one is totally guesswork.
strcat — I'd guess this is doing string concatenation of its arguments, as it has the name of a standard C function that does that (doing anything else would be weird and designed to trip its own programmer up).
That last line would be more conventionally written:
append hexStr $topb $botb
as the append command is optimised (in its memory management, which tends to dominate these sorts of things) for the building-a-string-piecemeal case. In particular, it doesn't demonstrate quadratic Shlemiel the painter misbehaviour.

There is nothing like the local standard keyword in Tcl.
for {set i 0 } { $i < $bsLen } { incr i } {
set topb [bs rhex $bsStream 1]
set botb [bs rhex $bsStream 1]
sethexStr [strcat $hexStr $topb $botb ]
}
for {initialize} {condition_check} {inclriment} {body to execute}

Related

Concise (one line?) binary search in Raku

Many common operations aren't built in to Raku because they can be concisely expressed with a combination of (meta) operators and/or functions. It feels like binary search of a sorted array ought to be expressable in that way (maybe with .rotor? or …?) but I haven't found a particularly good way to do so.
For example, the best I've come up with for searching a sorted array of Pairs is:
sub binary-search(#a, $target) {
when +#a ≤ 1 { #a[0].key == $target ?? #a[0] !! Empty }
&?BLOCK(#a[0..^*/2, */2..*][#a[*/2].key ≤ $target], $target)
}
That's not awful, but I can't shake the feeling that it could be an awfully lot better (both in terms of concision and readability). Can anyone see what elegant combo of operations I might be missing?
Here's one approach that technically meets my requirements (in that the function body it fits on a single normal-length line). [But see the edit below for an improved version.]
sub binary-search(#a, \i is copy = my $=0, :target($t)) {
for +#a/2, */2 … *≤1 {#a[i] cmp $t ?? |() !! return #a[i] with i -= $_ × (#a[i] cmp $t)}
}
# example usage (now slightly different, because it returns the index)
my #a = ((^20 .pick(*)) Z=> 'a'..*).sort;
say #a[binary-search(#a».key, :target(17))];
say #a[binary-search(#a».key, :target(1))];
I'm still not super happy with this code, because it loses a bit of readability – I still feel like there could/should be a concise way to do a binary sort that also clearly expresses the underlying logic. Using a 3-way comparison feels like it's on that track, but still isn't quite there.
[edit: After a bit more thought, I came up with an more readable version of the above using reduce.
sub binary-search(#a, :target(:$t)) {
(#a/2, */2 … *≤.5).reduce({ $^i - $^pt×(#a[$^i] cmp $t || return #a[$^i]) }) && Nil
}
In English, that reads as: for a sequence starting at the midpoint of the array and dropping by 1/2, move your index $^i by the value of the next item in the sequence – with the direction of the move determined by whether the item at that index is greater or lesser than the target. Continue until you find the target (in which case, return it) or you finish the sequence (which means the target wasn't present; return Nil)]

How does the interpretive program(ex:perl,shell) work

I propose a hypothesis: 1. the operating system creates a process space to start the interpreter; 2. the interpreter creates a new process space to start the program that needs to be interpreted, translating the first statement into machine language; 3. the execution of the first statement ends and interrupts; 4. the interpreter translates the next statement and dynamically modifies and creates new instructions. Well, I can't make it up. I can't understand the concept of explaining and executing.
Here's a example interpreter:
while (<>) {
my ($cmd, #args) = split;
if ($cmd eq '...') { ... }
elsif ($cmd eq '...') { ... }
elsif ($cmd eq '...') { ... }
else { ... }
}
This points out that the interpreted program isn't run in a separate process from the interpreter.
This also points out there isn't necessarily any translation to machine language.
Due note that Perl is a compiled language rather than interpreted one.
$ perl -MO=Concise,-exec -e'print("Hello, world!\n");'
1 <0> enter
2 <;> nextstate(main 1 -e:1) v:{
3 <0> pushmark s
4 <$> const[PV "Hello, world!\n"] s
5 <#> print vK
6 <#> leave[1 ref] vKP/REFC
-e syntax OK
That said, the compiled form is not native instructions. There are different ways this can be handled, but Perl effectively interprets these. The following is that interpreter:
int
Perl_runops_standard(pTHX)
{
OP *op = PL_op;
PERL_DTRACE_PROBE_OP(op);
while ((PL_op = op = op->op_ppaddr(aTHX))) {
PERL_DTRACE_PROBE_OP(op);
}
PERL_ASYNC_CHECK();
TAINT_NOT;
return 0;
}
(Copied from here.)
The ops are really data structures arranged in a linked list (with other pointers for jumps) rather than a stream of bytes encoding instructions. The above loop traverses the list, executing the function associated with each op. These function returns the address of the next op to execute, thus forming the program.
Some languages probably take a similar approach. Other languages definitely take a different approach.

Inline if with else

I realize that it's not valid ruby but what would be the technical hurdles to implement the below functionality into the Ruby core language (of say v2.3)?
variable = 1 if condition else -1
I'd also like to allow the following for more generic use.
variable = { 1 } if condition else { -1 }
I'm very open to requiring an "end" at the end.
I get that a ternary can easily accomplish this but I'm looking for a more readable inline-if that allows an else.
I get that I can make a function which does this via any number of styles but I'd prefer to have it as readable as possible.
Thanks.
EDIT: I hate editing questions for obvious reasons.
In response to the question of how the generic option is more ruby-esque, see the below example (I needed newlines).
variable = {
operation_one
operation_two
...
SUCCESS_STATUS_CODE
} if loaded_dependencies else {
do_detailed_logging
FAILURE_STATUS_CODE
}
if variable then
it_worked
else
explain_why
end
Because your example, while it seems readable to you, has too many ambiguities in other cases.
Not to mention that ruby has a way to do this, and it's the ternary operator. To say that your example is more ruby-like, is almost like wondering why the wheelbase of the Ford Mustang wasn't longer, and that it would be more "Mustang-like" if it was.
But here are some issues with your proposal, starting from your example:
variable = { 1 } if condition else { -1 }
Here you've given your "if else" bit a lower precedence than the "=".
In other words:
variable = ({ 1 } if condition else { -1 })
That's a serious problem, because it breaks the currently allowed:
variable = 1 if condition
The precedence for that statement is:
(variable = 1) if condition
And that's important. No assignment happens if the condition is false.
This can be a really big deal, for example if the lvalue (left side) actually has side-effects. For example:
var[0] = 1 if condition
The lookup for "var[0]" is a method in whatever class object var is, and while [] doesn't usually have side-effects, it can - and now you are going to do those side effects even if the condition is false.
And I won't even get into:
variable = { 1 } if condition if condition2 else { -1 }
But if you don't like it, you can always write your own language and see what happens!

Check Registry Version using Perl

I need to go to the registry and check a programs installed version. I am using perl to a whole lot of others things but the registry checking part isn't working. The program version has to be 9.7 and up so it could be 9.8 or 9.7.5.
When I install the program it shows 9.7.4 but I just need the 9.7 to be checked.
Bellow is me going to DisplayVersion which is a REG_SZ which shows 9.7.4.
OR
I could use VersionMajor and VersionMinor together which is a REG_DWORD. Which for Major is 9 and Minor is 7.
$ProgVersion= `$rootpath\\system32\\reg\.exe query \\\\$ASSET\\HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{9ACB414D-9347-40B6-A453-5EFB2DB59DFA} \/v DisplayVersion`;
if ($ProgVersion == /9.7/)
This doesn't work I could make it 9.200 and it still works. I tried to use this instead and it still wouldn't work. This next part is assuming that a new client needs to be install if it goes from 9.7. I was trying to use Great than or equal to, but it didn't work.
$ProgVersionMajor= `$rootpath\\system32\\reg\.exe query \\\\$ASSET\\HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{9ACB414D-9347-40B6-A453-5EFB2DB59DFA} \/v VersionMajor`;
$ProgVersionMinor= `$rootpath\\system32\\reg\.exe query \\\\$ASSET\\HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{9ACB414D-9347-40B6-A453-5EFB2DB59DFA} \/v VersionMinor`;
if (($ProgVersionMajor=~ /9/) && ($ProgVersionMinor=~ /7/))
Any help on doing this correctly or fixing what I am doing.
Several things:
You don't mention it, but are you using the Perl module Win32::TieRegistry? If not, you should. It'll make handling the Windows registry much easier.
In the Perl documentation, you can look at Version String under Scalar Value Constructors. This will make manipulating version strings much, much easier. Version strings have either more than one decimal place in them, or start with the letter v. I always prefix them with v to make it obvious what it is.
Here's a sample program below showing you how they can be used in comparisons:
#! /usr/bin/env perl
#
use strict;
use warnings;
my $version = v4.10.3;
for my $testVersion (v3.5.2, v4.4.1, v5.0.1) {
if ($version gt $testVersion) {
printf qq(Version %vd is greater than test %vd\n), $version, $testVersion;
}
else {
printf qq(Version %vd is less than test %vd\n), $version, $testVersion;
}
}
Note that I can't just print version strings. I have to use printf and sprintf and use the %vd vector decimal format to print them out. Printing version strings via a regular print statement can cause all sorts of havoc since they're really unicode representations. You put them in a print statement and you don't know what you're getting.
Also notice that you do not put quotes around them! Otherwise, you'll just make them regular strings.
NEW ANSWER
I was trying to find a way to convert a string into a v-string without downloading an optional package like Perl::Version or (Version), and I suddenly read that v-strings are deprecated, and I don't want to use a deprecated feature.
So, let's try something else...
We could simply divide up version numbers into their constituent components as arrays:
v1.2.3 => $version[0] = 1, $version[1] = 2, $version[2] = 3
By using the following bit of code:
my #version = split /\./, "9.7.5";
my #minVersion = split /\./, "9.7"
Now, we can each part of the version string against the other. In the above example, I compare the 9 of #version with the 9 of #version, etc. If #version was 9.6 I would have compared the 6 in #version against the 7 in #minVersion and quickly discovered that #minVersion is a higher version number. However, in both the second parts are 7. I then look at the third section. Whoops! #minVersion consists of only two sections. Thus, #version is bigger.
Here's a subroutine that does the comparison. Note that I also verify that each section is an integer via the /^\d+$/ regular expression. My subroutine can return four values:
0: Both are the same size
1: First Number is bigger
2: Second Number is bigger
undef: There is something wrong.
Here's the program:
my $minVersion = "10.3.1.3";
my $userVersion = "10.3.2";
# Create the version arrays
my $result = compare($minVersion, $userVersion);
if (not defined $results) {
print "Non-version string detected!\n";
}
elsif ($result == 0) {
print "$minVersion and $userVersion are the same\n";
}
elsif ($result == 1) {
print "$minVersion is bigger than $userVersion\n";
}
elsif ($result == 2) {
print "$userVersion is bigger than $minVersion\n";
}
else {
print "Something is wrong\n";
}
sub compare {
my $version1 = shift;
my $version2 = shift;
my #versionList1 = split /\./, $version1;
my #versionList2 = split /\./, $version2;
my $result;
while (1) {
# Shift off the first value for comparison
# Returns undef if there are no more values to parse
my $versionCompare1 = shift #versionList1;
my $versionCompare2 = shift #versionList2;
# If both are empty, Versions Matched
if (not defined $versionCompare1 and not defined $versionCompare2) {
return 0;
}
# If $versionCompare1 is empty $version2 is bigger
if (not defined $versionCompare1) {
return 2;
}
# If $versionCompare2 is empty $version1 is bigger
if (not defined $versionCompare2) {
return 1;
}
# Make sure both are numeric or else there's an error
if ($versionCompare1 !~ /\^d+$/ or $versionCompare2 !~ /\^\d+$/) {
return;
}
if ($versionCompare1 > $versionCompare2) {
return 1;
}
if ($versionCompare2 > $versionCompare1) {
return 2;
}
}
}
Using Win32::TieRegistry
You said in your answer you didn't use Win32::TieRegistry. I just want to show you what it can do for the readability of your program:
Your Way
$ProgVersion= `$rootpath\\system32\\reg\.exe query \\\\$ASSET\\HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{9ACB414D-9347-40B6-A453-5EFB2DB59DFA} \/v DisplayVersion`;
With Win32::TieRegistry
use Win32::TieRegistry ( TiedHash => '%RegHash', DWordsToHex => 0 );
my $key = $TiedHash->{LMachine}->{Software}->{Wow6432Node}->{Microsoft}->{Windows}->{CurrentVersion}->{Uninstall}->{9ACB414D-9347-40B6-A453-5EFB2DB59DFA}->{Version};
my $programValue = $key->GetValue;
my $stringValue = unpack("L", $programValue);
Or, you can split it up:
my $MSSoftware = $TiedHash->{LMachine}->{Software}->{Wow6432Node}->{Microsoft};
my $uninstall = $MSSoftware->{Windows}->{CurrentVersion}->{Uninstall};
my $programVersion = $uninstall->{9ACB414D-9347-40B6-A453-5EFB2DB59DFA}->{Version};
See how much easier that's to read. You can also use this to test keys too.
(Word 'o Warning: I don't have a Windows machine in front of me, so I didn't exactly check the validity of the code. Try playing around with it and see what you get.)

nice way of doing 'if ALL items in collection pass test'

I mean this:
bool passed = true;
for(int i = 0; i < collection.Length; i++)
{
if(!PassesTest(collection[i]))
{
passed = false;
break;
}
}
if(passed){/*passed code*/}
requires extra variable, extra test
for(int i = 0; i < collection.Length; i++)
{
if(!PassesTest(collection[i]))
{
return;
}
}
{/*passed code*/}
neat, but requires this to be it's own function, if this it's self is inside a loop or something, not the most performant way of doing things. also, writing a whole extra function is a pain
if(passed){/*passed code*/}
for(int i = 0; i < collection.Length; i++)
{
if(!PassesTest(collection[i]))
{
goto failed;
}
}
{/*passed code*/}
failed: {}
great, but you have to screw around with label names and ugly label syntax
for(int i = 0; ; i++)
{
if(!(i < collection.Length))
{
{/*passed code*/}
break;
}
if(!PassesTest(collection[i]))
{
break;
}
}
probably the nicest, but still a bit manual, kinda wasting the functionality of the for loop construct, for instance, you can't do this with a foreach
what is the nicest way to handle this problem?
it seems to me something like this would be nice:
foreach(...)
{
...
}
finally{...} // only executed if loop ends conventionally (without break)
am I missing something? because this is a very common problem for me, and I don't really like any of the solutions I've come up with.
I use c++ and C#, so solutions in either would be great.
but would also be interested in solutions in other languages. (though a design principle that avoids this in any language would be ideal)
If your language doesn't have this feature, write a function "forall," which takes two arguments: a list and a boolean-valued function which is to be true for all elements of the list. Then you only have to write it once, and it matters very little how idiomatic it is.
The "forall" function looks exactly like your second code sample, except that now "collection" and "passesTest" are the arguments to that function.
Calling forall looks roughly like:
if (forall(myList,isGood)) {
which is readable.
As an added bonus, you could implement "exists" by calling "forall" on the negated boolean function, and negating its answer. That is, "exists x P(x)" is implemented as "not forall x not P(x)".
You can use Linq in .NET.
Here's an example in C#:
if(collection.All(item => PassesTest(item)))
{
// do my code
}
C++ and STL
if (std::all_of(collection.begin(), collection.end(), PassesTest))
{
/* passed code */
}
Ruby:
if collection.all? {|n| n.passes_test?}
# do something
end
Clojure:
(if (every? passes-test? collection)
; do something
)
Groovy:
if (!collection.find { !PassesTest(it) }) {
// do something
}
Scala:
def passesTest(i: Int) = i < 5 // example, would likely be idiomatically in-line
var seq = List(1,2,3,4);
seq.forall(passesTest) // => True
Most, if not all of the answers presented here are saying: higher-order constructs -- such as "passing functions" -- are really, really nice. If you are designing a language, don't forget about the last 60+ years of programming languages/designs.
Python (since v2.5):
if all(PassesTest(c) for c in collection):
do something
Notes:
we can iterate directly on collection, no need for an index and lookup
all() and any() builtin functions were added in Python 2.5
the argument to any(), i.e. PassesTest(c) for c in collection, is a generator expression. You could also view it as a list comprehension by adding brackets [(PassesTest(c) for c in collection]
... for c in collection causes iteration through a collection (or sequence/tuple/list). For a dict, use dict.keys(). For other datatypes, use the correct iterator method.

Resources