“P6opaque, Str” vs simple “Str” types in Perl 6 - string

This is a follow-up to my previous question.
I am finally able to reproduce the error here:
my #recentList = prompt("Get recentList: e.g. 1 2 3: ").words || (2,4,6);
say "the list is: ", #recentList;
for #recentList -> $x {
say "one element is: ", $x;
say "element type is: ", $x.WHAT;
say "test (1,2,3).tail(\"2\") : ", (1,2,3).tail("2");
say ( (10.rand.Int xx 10) xx 15 ).map: { #($_.tail($x)); };
}
And the results are ok as long as I use the default list by just hitting return at the prompt and not entering anything. But if I enter a number, it gives this error:
Get recentList: e.g. 1 2 3: 2
the list is: [2]
one element is: 2
element type is: (Str)
test (1,2,3).tail("2") : (2 3)
This type cannot unbox to a native integer: P6opaque, Str
in block at intType.p6 line 9
in block <unit> at intType.p6 line 5
If tail("2") works, why does tail($x) fail? Also, in my original code, tail($x.Int) wouldn't correct the problem, but it did here.

This is at best a nanswer. It is a thus-far failed attempt to figure out this problem. I may have just wandered off into the weeds. But I'll publish what I have. If nothing else, maybe it can serve as a reminder that the first three steps below are sensible ones; thereafter I'm gambling on my ability to work my way forward by spelunking source code when I would probably make much faster and more reliable progress by directly debugging the compiler as discussed in the third step.
OK, the first step was an MRE. What you've provided was an E that was fully R and sufficiently M. :)
Step #2 was increasing the M (golfing). I got it down to:
Any.tail('0'); # OK
Any.tail('1'); # BOOM
Note that it can be actual values:
1.tail('1'); # BOOM
(1..2).tail('1'); # BOOM
But some values work:
(1,2).tail('1'); # OK
Step #3 probably should be to follow the instructions in Playing with the code of Rakudo Perl 6 to track the compiler's execution, eg by sticking says in its source code and recompiling it.
You may also want to try out App::MoarVM::Debug. (I haven't.)
Using these approaches you'll have the power to track with absolute precision what the compiler does for any code you throw at it. I recommend you do this even though I didn't. Maybe you can figure out where I've gone wrong.
In the following I trace this problem by just directly spelunking the Rakudo compiler's source code.
A search for "method tail" in the Rakudo sources yielded 4 matches. For my golf the matching method is a match in core/AnyIterableMethods.pm6.
The tail parameter $n clearly isn't a Callable so the pertinent line that continues our spelunking is Rakudo::Iterator.LastNValues(self.iterator,$n,'tail').
A search for this leads to this method in core/Iterator.pm6.
This in turn calls this .new routine.
These three lines:
nqp::if(
n <= 0, # must be HLL comparison
Rakudo::Iterator.Empty, # negative is just nothing
explain why '0' works. The <= operator coerces its operands to numeric before doing the numeric comparison. So '0' coerces to 0, the condition is True, the result is Rakudo::Iterator.Empty, and the Any.tail('0') yields () and doesn't complain.
The code that immediately follows the above three lines is the else branch of the nqp::if. It closes with nqp::create(self)!SET-SELF(iterator,n,f).
That in turn calls the !SET-SELF routine, which has the line:
($!lastn := nqp::setelems(nqp::list, $!size = size)),
Which attempts to assign size, which in our BOOM case is '1', to $!size. But $!size is declared as:
has int $!size;
Bingo.
Or is it? I don't know if I really have correctly tracked the problem down. I'm only spelunking the code in the github repo, not actually running an instrumented version of the compiler and tracing its execution, as discussed as the sensible step #3 for trying to figure out the problem you've encountered.
Worse, when I'm running a compiler it's an old one whereas the code I'm spelunking is the master...
Why does this work?
(*,*).tail('1') # OK
The code path for this will presumably be this method. The parameter $n isn't a Callable so the code path will run thru the path that uses the $n in the lines:
nqp::unless(
nqp::istype($n,Whatever) || $n == Inf,
$iterator.skip-at-least(nqp::elems($!reified) - $n.Int)
The $n == Inf shouldn't be a problem. The == will coerce its operands to numerics and that should take care of $n being '1'.
The nqp::elems($!reified) - $n.Int shouldn't be a problem either.
The nqp ops doc shows that nqp::elems always returns an int. So this boils down to an int - Int which should work.
Hmm.
A blame of these lines shows that the .Int in the last line was only added 3 months ago.
So, clutching at straws, what happens if one tries:
(my int $foo = 1) - '1' # OK
Nope, that's not the problem.
It seems the trail has grown cold or rather I've wandered off the actual execution path.
I'll publish what I've got. Maybe someone else can pick it up from here or I'll have another go in a day or three...

Related

How can i specify parameter dependent on index value?

I'm trying to port code from DML 1.2 to DML 1.4. Here is part of code that i ported:
group rx_queue [i < NQUEUES] {
<...>
param desctype = i < 64 #? regs.SRRCTL12[i].DESCTYPE.val #: regs.SRRCTL2[i - 64].DESCTYPE.val; // error occurs here
<...>
}
Error says:
error: non-constant expression: cast(i, int64 ) < 64
How can i specify parameter dependent on index value?
I tried to use if...else instead ternary operator, but it says that conditional parameters are not allowed in DML.
Index parameters in DML are a slightly magical expressions; when used from within parameters, they can evaluate to either a constant or a variable depending on where the parameter is used from. Consider the following example:
group g[i < 5] {
param x = i * 4;
method m() {
log info: "%d", x;
log info: "%d", g[4 - i].x;
log info: "%d", g[2].x;
}
}
i becomes an implicit local variable within the m method, and in params, indices are a bit like implicit macro parameters. When the compiler encounters x in the first log statement, the param will expand to i * 4 right away. In the second log statement, the x param is taken from an object indexed with the expression 4 - i, so param expansion will instead insert (5 - i) * 4. In the third log statement, the x param is taken from a constant indexed object, so it expands to 2 * 4 which collapses into the constant 8.
Most uses of desctype will likely happen from contexts where indices are variable, and the #? expression requires a constant boolean as condition, so this will likely give an error as soon as anyone tries to use it.
I would normally advise you to switch from #? to ? in the definition of the desctype param, but that fails in this particular case: DMLC will report error: array index out of bounds on the i - 64 expression. This error is much more confusing, and happens because DMLC automatically evaluates every parameter once with all zero indices, to smoke out misspelled identifiers; this will include evaluation of SRRCTL2[i-64] which collapses into SRRCTL2[-64] which annoys DMLC.
This is arguably a compiler bug; DMLC should probably be more tolerant in this corner. (Note that even if we would remove the zero-indexed validation step from the compiler, your parameter would still give the same error message if it ever would be explicitly referenced with a constant index, like log info: "%d", rx_queue[0].desctype).
The reason why you didn't get an error in DML 1.2 is that DML 1.2 had a single ternary operator ? that unified 1.4's ? and #?; when evaluated with a constant condition the dead branch would be disregarded without checking for errors. This had some strange effects in other situations, but made your particular use case work.
My concrete advise would be to replace the param with a method; this makes all index variables unconditionally non-constant which avoids the problem:
method desctype() -> (uint64) {
return i < 64 ? regs.SRRCTL12[i].DESCTYPE.val : regs.SRRCTL2[i - 64].DESCTYPE.val;
}

Why does the expression: If (A:=!A) evaluate differently each time a hotkey is pressed?

In an Autohotkey script, once a user presses the CapsLock key, a SplashText should pop up indicating that it is ON, or out when it is OFF, the problem here is not about the code that gets it to work but how much simpler it can get.
There are different ways that do it, some need about 25 lines, some use SetTimer and GetKeyState internal functions and several loops to get it to run, some just about five and no loops.
Simplest:
#SingleInstance Force
SetCapsLockState, Off
~CapsLock::
If (Tog:=!Tog)
SplashTextOn ,350 ,35 , Wanted !, [CapsLock] Activated.
else
SplashTextOff
return
How does: If (Tog:=!Tog) get this code running so easily? Tog is just a variable not initiated, and each time the CapsLock is pressed it is continuously changing its value from 1 to 0
It seems to be acting as a Flag in the code? what am I missing in this line:
If (Tog:=!Tog)
What makes it evaluate different each time?
This is one below is another approach with A = 0 working as a switch, I made this one and it doesn't quite get as simple as I'd like it to be but it does the job.
Longer code:
#SingleInstance Force
SetCapsLockState, Off
~CapsLock::
If (A = 0)
{
SplashTextOn ,350 ,35 , Wanted !, [CapsLock] Activated.
A=1
}else
{
SplashTextOff
A=0
}
return
Longest code:
This last one gets the same result but checks the actual physical state of the key It wouldn't rely on SetCapsLockState, Off at the top of the script to make sure a switch will do the rest of the work in just one line as the simpler one.
#SingleInstance Force
#Persistent
SetTimer, StateCapsLockON_Timer, 100
Return
~CapsLock::
StateCapsLockON_Timer
If GetKeyState("CapsLock", "T")
{
SetTimer, StateCapsLockOFF_Timer, 100
SplashTextOn ,350 ,35 , Wanted !, [CapsLock] Activated.
SetTimer, StateCapsLockON_Timer, Off
}
Return
StateCapsLockOFF_Timer:
If !GetKeyState("CapsLock", "T")
{
SetTimer, StateCapsLockOFF_Timer, Off
SplashTextOff
SetTimer, StateCapsLockON_Timer, On
}
Return
Any good ideas about the way If (Tog:=!Tog) works in the simplest of these three examples?
I got this now, check logical-not on this link:
https://lexikos.github.io/v2/docs/Variables.htm
If the operand (In this case Tog) is blank or 0, the result of applying logical-not (or !Tog) is 1, which means "true". Otherwise, the result is 0 (false)
if (Tog = 0)
Tog = 1
would bring the same result as:
If Tog:=!Tog
Because an operation was taking place before the If even checked the changed value, if wasn't just comparing data, the operation was happening before the if since the values inside the parenthesis were not just being read but were also being changed and the variable being reassigned.
(expression) Any sub-expression enclosed in parentheses. For example, (3 + 2) * 2 forces 3 + 2 to be evaluated first.
The key difference is the usage of the assignment operator := as opposed to the comparing operator =. Since, as you've seen, you can evaluate expressions in an if-statement, you can actually include both operators in the same if-statement. Here's an example:
f1::
If (( test := 3+2 ) = 5 )
MsgBox
Return
Here "test" is first being assigned the sum of 3+2, then compared to 5. So, the key is that if-statements allow assignments to take place and that assignments take place first, that is, before anything is compared and evaluated to be true or false.
If there is no comparing operator (= , <, >, <=, >=), as is the case in your toggle, it just evaluates whether the variable itself is true or false. If the variable is blank, 0, or false, it evaluates to false; everything else is true, even the string "false".
Now for the fun bit. We can actually reduce your code to one line if we use Progress with the "zh0" option.
~CapsLock::Progress , % ( Tog := !Tog ) ? "zh0 w350 h35" : "Off" ,, [CapsLock] Activated. , Wanted !
Unfortunately, this isn't possible with SplashText since these are actually two separate commands. But the upside is that Progress actually has a lot more options available, so you can change the font size and color, etc.

When searching, Prolog gives correct answers but repeats them N times before searching another

Ok So i've got this Prolog code that represents an evolving world of blocks, and there's a robotic arm that can move 1 block at the time, and 2 little robots "rob and bor" that can paint blocks of their assigned color when the blocks are on top of a tower or on the bottom of a tower (See code for the conditions). function clear(X) is true when block X is on top of a tower, and ontable(X) is true when X is on the table (at the bottom of a tower). Single block towers return both clear and ontable as true.
The code aims to give all the solutions, step by step, when asked for a particular state (Like all 4 blocks on a single tower and red painted).
For that, there's a set of actions and facts defined, their conditioning effects (When action A is done under conditions C, what happens to the fact F) and a possibility/reality check with functions poss(returns true if some action is possible to do) and holds(returns true if some fact is true) that work on every state S. legal is the mix of these 2(Something is legal if everything in it holds and is possible).
%% Object Declaration (problem-specific)
block(B) :- member(B,[a,b,c,d]).
% colors available for rob and bor
color(rob,B) :- member(B,[blue]).
color(bor,B) :- member(B,[red]).
%% Initial Situation (problem-specific)
holds(F,s0) :- member(F,[on(a,b),on(b,c),ontable(c), ontable(d), clear(a), clear(d)]).
holds(color(B,white),s0) :- block(B).
%% Blocks World Preconditions (domain-specific)
%% action move_to_block(X,Z) moves block X on top of block Z
% poss is true when its possible to do the action.
poss(move_to_block(X,Z),S) :-
holds(clear(X),S), holds(clear(Z),S), Z\=X, \+ holds(on(X,Z),S).
poss(move_to_table(X),S) :-
holds(clear(X),S), \+ holds(ontable(X),S).
%% Robot R paints block B of color C
poss(paint(rob,B,C),S) :-
color(rob,C),holds(clear(B),S), \+ holds(color(B,C),S).
poss(paint(bor,B,C),S) :-
color(bor,C), holds(ontable(B),S), \+ holds(color(B,C),S).
%% Blocks World Effects (domain-specific)
% is_conditional_negative_effect(Act,Cond,Fact)
% when Act is peformed and Cond holds, Fact becomes false
is_conditional_negative_effect(move_to_block(X,_),on(X,Y),on(X,Y)).
is_conditional_negative_effect(move_to_block(X,_),ontable(X),ontable(X))
is_conditional_negative_effect(move_to_block(X,Z),true,clear(Z)).
is_conditional_negative_effect(move_to_table(X),on(X,_),on(X,_)).
is_conditional_negative_effect(paint(R,B,C),color(B,D),color(B,D)).
% is_conditional_positive_effect(Act,Cond,Fact)
% when Act is peformed and Cond holds, Fact becomes true
is_conditional_positive_effect(move_to_block(X,_),on(X,Y),clear(Y)).
is_conditional_positive_effect(move_to_block(X,Z),true ,on(X,Z)).
is_conditional_positive_effect(move_to_block(X,_),true,clear(X)).
is_conditional_positive_effect(move_to_table(X),true ,ontable(X)).
is_conditional_positive_effect(move_to_table(X),on(X,Y),clear(Y)).
is_conditional_positive_effect(move_to_table(X),true,clear(X)).
is_conditional_positive_effect(paint(R,B,C),color(B,_),color(B,C)).
holds(true,s0). % "true" always holds
holds(F,do(A,S)) :-
holds(F,S),
\+ (is_conditional_negative_effect(A,C,F), holds(C,S)).
holds(F,do(A,S)) :-
is_conditional_positive_effect(A,C,F),holds(C,S).
% S is legal if it is the result of performing executable actions
legal(s0).
legal(do(A,S)) :-
legal(S),
poss(A,S).
So thing is, when a consult done like follows ( time() only makes that the given answer returns the process time, for optimization sake... that's another problem i'll check later):
time((legal(S), holds(on(b,d),S), holds(on(c,b),S), holds(on(a,c),S), holds(color(b,blue),S), holds(color(a,red),S))).
SO far I get correct answers, but repeated like 10 times before it gives another, (correct too), so if I want all the answers, I've got to smash the ; like ten thousand times. I've been approximately 3 hours trying to solve this issue, since it doesn't let me check if I get all the correct answers or something is missing. Do you guys figure out what's going on?.
Tried to make everything as clear as possible, but comment if you need me to clarify something!
Finally, with a friend, we managed to fix it, the problem was on the positive conditional effects, specifically those related to clear. These affirmations were obvious, since a block must already return true to clear before being moved:
is_conditional_positive_effect(move_to_block(X,_),true,clear(X)).
is_conditional_positive_effect(move_to_table(X),true,clear(X)).
Also I changed some conditionals to be more specific, these greately improved the performance of the search:
is_conditional_negative_effect(move_to_table(X),on(X,_),on(X,_)).
was replaced by
is_conditional_negative_effect(move_to_table(X),on(X,Y),on(X,Y)).
and
is_conditional_positive_effect(paint(R,B,C),color(B,_),color(B,C)).
was replaced by
is_conditional_positive_effect(paint(R,B,C),true,color(B,C)).
Credits to my mate Pablo.

Can I introspect a variable to directly discover what subset it was declared with?

Is there a way to introspect a variable to directly find out what subset it was declared with? Here I create a subset, but introspection points me to its base type:
> subset Prime of Int where .is-prime
(Prime)
> my Prime $x = 23
23
> $x.WHICH
Int|23
I know it has to store the information somewhere, because if I try to reassign a value that doesn't match the subset, it fails:
> $x = 24
Type check failed in assignment to $x; expected Prime but got Int (24)
in block <unit> at <unknown file> line 1
I tried searching through the code, but I quickly get down into files like container.c and perl6_ops.c where the C code makes my eyes glaze over. I thought that X::TypeCheck::Assignment might help (see core/Exception.pm), but it's not clear to me where the expected value comes from. (see also this commit)
I feel like I'm missing something obvious.
I can check that something matches a subset, but that doesn't tell me if it were declared with a particular subset:
> my Int $y = 43;
43
> $y ~~ Prime;
True
I'm using Rakudo Star 2017.01
Inspired by a Zoffix's use of subsets in a recent post.
The value that you stored in $x is an Int. It is acceptable to the container (which you typed to Prime) because Prime is a subtype of Int.
So what you're interested in, is not the value in the container, but the type of the container. To get at the container, Perl 6 has the .VAR method. And that has an .of method to get at the type:
$ 6 'subset Prime of Int where .is-prime; my Prime $x; dd $x.VAR.of'
Prime

R: agrep error when replacing string with another string

after a lot of trial/error and the search function I am still somewhat clueless about an I-thought-simple-thing (as always, hrmpf):
I have a column in a data frame x$question and within that column, there is an expression 'A/V' every once in a while, and I simply want it to be changed to 'A / B'.
I tried a little here and there, and thought this should work:
x$question[agrep('A/V',x$question)]<-'A / B'
but I get the error:
In `[<-.factor`(`*tmp*`, agrep('A/V', :
invalid factor level, NAs generated
or I could do this
agrep('A/V','A / B', x$question).
But here I get the error:
Error in .amatch_bounds(max.distance) :
match distance components must be non-negative
Since I am quite out of ideas, I would be very thankful, if you had a suggestions, or maybe an even simpler way of replacing a string with another string.
Does this work?
gsub("A/V","A/B",x$question)
Example:
x<-c("A/V", "A/V", "A/V")
x<-gsub("A/V","A/B",x)
>x
[1] "A/B" "A/B" "A/B"
Note: You can use ifelse for that too.
> ifelse(x=="A/B","A/V",x)
[1] "A/V" "A/V" "A/V"

Resources