Assignment to nested lists in Perl 6 - raku

I supposed, the result should be 1, 2, 3.
> my ($a, $b, $c)
> (($a, $b), $c) = ((1, 2), 3)
(((1 2) 3) (Any))
> $a, $b, $c
((1 2) 3 (Any))
What's wrong here?

There's nothing wrong (that is, ordinary assignment in P6 is designed to do as it has done) but at a guess you were hoping that making the structure on the two sides the same would result in $a getting 1, $b getting 2 and $c getting 3.
For that, you want "binding assignment" (aka just "binding"), not ordinary assignment:
my ($a, $b, $c);
:(($a, $b), $c) := ((1, 2), 3);
Note the colon before the list on the left, making it a signature literal, and the colon before the =, making it a binding operation.

If you want to have the result be 1, 2, 3, you must Slip the list:
my ($a, $b, $c) = |(1, 2), 3;
This is a consequence of the single argument rule: https://docs.raku.org/type/Signature#Single_Argument_Rule_Slurpy
This is also why this just works:
my ($a, $b, $c) = (1, 2, 3);
Even though (1,2,3) is a List with 3 elements, it will be auto-slipped because of the same single argument rule. You can of course also just remove the (superstitious) parentheses:
my ($a, $b, $c) = 1, 2, 3;

You are asking *What's wrong here", and I would say some variant of the single argument rule is at work. Since parentheses are only used here for grouping, what's going on is this assignment
($a, $b), $c = (1, 2), 3
(1, 2), 3 are behaving as a single argument, so they are slurpily assigned to the first element in your group, $a, $b. Thus they get it all, and por old $c only gets Any. Look at it this way:
my ($a, $b, $c);
($a, ($b, $c)) = ((1, 2), 3, 'þ');
say $a, $c; # OUTPUT: «(1 2)þ␤»
You might want to look at this code by Larry Wall, which uses »=«, which does exactly what you are looking for. It's not documented, so you might want to wait a bit until it is.

Related

TCL can’t use variable substitution inside curly brackets

I'm having a problem where variables are being interpreted as a string rather than the intended value.
I'm trying to append pairs of numbers to a list, grouped by curlys, but it doesn't work with variable substitution.
set new_list {}
lappend new_list {4 5}
lappend new_list {7 8}
puts "$list"
Output:
{4 5} {7 8}
This is the desired format.
However when I try the following, let's say for instance I wanted all integers to 10 and their squared value to be appended to the list as pairs:
for {set i 0} {$i < 10} {incr i} {
lappend new_list {$i [expr pow($i, 2)]}
}
Output:
{$i [expr pow($i, 2)]} {$i [expr pow($i, 2)]} {$i [expr pow($i, 2)]} {$i [expr pow($i, 2)]} .... and so on ....
I'd want the values as integer pairs: {1 1} {2 4} {3 9} ...
Any help in achieving this?
You have to evaluate the words (expressions, etc) at the time that you do the lappend. To do that, you build the sublist to be appended with the list construction command:
for {set i 0} {$i < 10} {incr i} {
lappend new_list [list $i [expr {$i ** 2}]]
}
Braces by themselves mean “do not expand anything in this now”. (That's their actual meaning in Tcl. It's just that some commands, such as for, then go right ahead and do their thing with what's inside them immediately.) You could, in this case, have put the things to insert in double quotes, but that's bad practice as it can bite you hard once you start using real-world data (such as people's surnames with spaces in); the list command is specifically designed (and thoroughly tested) to have no such weaknesses.
In this specific case, I'd write $i ** 2 instead of pow($i, 2) because the latter always produces a floating point result, whereas the former is sensitive to numeric types (just like other expr operators).

Cumulative Z op throws a "The iterator of this Seq is already in use/consumed by another Seq"

This is another way of solving previous question
my #bitfields;
for ^3 -> $i {
#bitfields[$i] = Bool.pick xx 3;
}
my #total = [\Z+] #bitfields;
say #total;
It should zip-add every row to the next one, and accumulate the value. However, this yields the error
The iterator of this Seq is already in use/consumed by another Seq
(you might solve this by adding .cache on usages of the Seq, or
by assigning the Seq into an array)
in block <unit> at vanishing-total.p6 line 8
Any idea how this might be solved?
First xx creates a Sequence
say (Bool.pick xx 3).^name; # Seq
So you probably want to turn that into an Array (or List).
for ^3 -> $i {
#bitfields[$i] = [Bool.pick xx 3];
}
Also rather than .pick xx 3, I would use .roll(3).
for ^3 -> $i {
#bitfields[$i] = [Bool.roll(3)];
}
The zip (Z) meta operator creates Sequences as well.
say ( [1,2] Z [3,4] ).perl;
# ((1, 3), (2, 4)).Seq
say ( [1,2] Z+ [3,4] ).perl
# (4, 6).Seq
So [\Z+] won't even work the way you want for two inputs.
say [\Z+]( [1,2], [3,4] ).perl;
# (Seq.new-consumed(), Seq.new-consumed()).Seq
say [\Z+]( 1, 2 ).perl;
# (Seq.new-consumed(), Seq.new-consumed()).Seq
It does work if you do something to cache the intermediate values.
say [\Z+]( [1,2], [3,4] ).map(*.cache).perl
# ((3,), (4, 6)).Seq
say [\Z+]( [1,2], [3,4] ).map(*.list).perl
# ((3,), (4, 6)).Seq
say [\Z+]( [1,2], [3,4] ).map(*.Array).perl
# ([3], [4, 6]).Seq
You might want to also add a list to the front, and a .skip.
my #bitfields = [
[Bool::True, Bool::True, Bool::False],
[Bool::False, Bool::False, Bool::True ],
[Bool::False, Bool::True, Bool::True ]
];
say [\Z+]( #bitfields ).map(*.List)
# ((2) (1 1 1) (1 2 2))
say [\Z+]( (0,0,0), |#bitfields ).map(*.List).skip
# ((1 1 0) (1 1 1) (1 2 2))
If you don't need the intermediate results [Z+] would work just fine.
say [Z+]( Bool.roll(3) xx 3 ) for ^5;
# (0 1 3)
# (1 2 1)
# (1 0 3)
# (0 1 2)
# (1 2 2)

Remove only the trailing elements of a Vec that match a condition

I have a Vec<T> that has elements matching a pattern. I want to remove all trailing instances of the elements that match the pattern.
For example, I have a Vec<i32> and the pattern is (|x| x == 0). If the input was: vec![0, 1, 0, 2, 3, 0, 0], the output should be: vec![0, 1, 0, 2, 3]
To do this I tried:
fn main() {
let mut vec = vec![0, 1, 0, 2, 3, 0, 0];
vec = vec.into_iter().rev().skip_while(|&x| x == 0).rev();
}
But I get these compiler errors:
error[E0277]: the trait bound `std::iter::SkipWhile<std::iter::Rev<std::vec::IntoIter<{integer}>>, [closure#src/main.rs:3:44: 3:55]>: std::iter::DoubleEndedIterator` is not satisfied
--> src/main.rs:3:57
|
3 | vec = vec.into_iter().rev().skip_while(|&x| x == 0).rev();
| ^^^ the trait `std::iter::DoubleEndedIterator` is not implemented for `std::iter::SkipWhile<std::iter::Rev<std::vec::IntoIter<{integer}>>, [closure#src/main.rs:3:44: 3:55]>`
error[E0308]: mismatched types
--> src/main.rs:3:11
|
3 | vec = vec.into_iter().rev().skip_while(|&x| x == 0).rev();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::vec::Vec`, found struct `std::iter::Rev`
|
= note: expected type `std::vec::Vec<{integer}>`
found type `std::iter::Rev<std::iter::SkipWhile<std::iter::Rev<std::vec::IntoIter<{integer}>>, [closure#src/main.rs:3:44: 3:55]>>`
The strange thing is that DoubleEndedIterator is implemented for SkipWhile. In fact, SkipWhile even implements rev(). See here.
What am I doing wrong? Is there a better approach?
The iterator adaptor for reversal only works for iterators which can be traversed from any of the two ends (as in, it is a DoubleEndedIterator). While this is the case for the original one, this is no longer possible from the moment we include skip_while. In order to follow that approach, you would have to collect the rest of the reversed vector, and only then reverse again.
I, on the other hand, would just choose to fetch the index of the first trailing zero and truncate the vector with it.
let mut vec = vec![0, 1, 0, 2, 3, 0, 0];
if let Some(i) = vec.iter().rposition(|x| *x != 0) {
let new_len = i + 1;
vec.truncate(new_len);
}
... or just grab a slice instead:
let piece = &vec[..new_len];
Playground
As the error messages state:
the trait DoubleEndedIterator is not implemented for SkipWhile<...> — Take a look at the implementation of SkipWhile:
pub struct SkipWhile<I, P> {
iter: I,
flag: bool,
predicate: P,
}
You cannot reverse an iterator built from SkipWhile because it has no way of tracking if the "current" item was skipped when you add in the ability to pull from the front and the back.
expected struct Vec, found struct Rev — You still have an iterator, but you are trying to store it where a Vec must be stored. You cannot put a type A where a type B is needed.
I would collect the vector and then reverse it in place:
fn main() {
let mut vec = vec![0, 1, 0, 2, 3, 0, 0];
vec = vec.into_iter().rev().skip_while(|&x| x == 0).collect();
vec.reverse();
println!("{:?}", vec);
assert_eq!(vec, [0, 1, 0, 2, 3]);
}
DoubleEndedIterator is implemented for SkipWhile.
This is not true. If you look at the documentation for SkipWhile, it does not list that it implements DoubleEndedIterator. Here's an example of a trait it does implement: FusedIterator.
In fact, SkipWhile even implements rev()
It doesn't actually. Iterator::rev is only implemented in the condition that Self (which is SkipWhile) implements DoubleEndedIterator, which this doesn't:
fn rev(self) -> Rev<Self>
where
Self: DoubleEndedIterator,
Just to get things started, here is a really dodgy solution:
fn main() {
let mut vec = vec![0, 1, 0, 2, 3, 0, 0];
vec = vec.into_iter().rev().skip_while(|&x| x == 0).collect();
vec = vec.into_iter().rev().collect();
}

It looks like the keyword "in" is used as a variable

Pasting the following code in http://elm-lang.org/try and clicking on "Compile" :
import Html exposing (text)
main =
let (x, y, _) = List.foldL (\elem (sum, diff, mult) ->
(sum + elem, elem - diff, mult * elem)
) (0, 0, 0) [1, 2, 3, 4, 5] in
text ("Hello, World!" ++ toString x)
results in an unexpected error:
Detected errors in 1 module.
-- SYNTAX PROBLEM ------------------------------------------------------------
It looks like the keyword in is being used as a variable.
7| ) (0, 0, 0) [1, 2, 3, 4, 5] in
^
Rename it to something else.
What is wrong here? Parentheses match.
Indentation is important in Elm, and you've got a closing parenthesis that is too far to the left (the second to last line). Changing it to this will be valid code (also, it's List.foldl, not foldL):
main =
let (x, y, _) = List.foldl (\elem (sum, diff, mult) ->
(sum + elem, elem - diff, mult * elem)
) (0, 0, 0) [1, 2, 3, 4, 5] in
text ("Hello, World!" ++ toString x)
It is probably more idiomatic to put the in statement on its own line, aligned with let, just for keeping things clear:
main =
let (x, y, _) = List.foldl (\elem (sum, diff, mult) ->
(sum + elem, elem - diff, mult * elem)
) (0, 0, 0) [1, 2, 3, 4, 5]
in
text ("Hello, World!" ++ toString x)
You could also incorporate elm-format into your editing process to automatically format your code on save.

How do I sum the coefficients of a polynomial in Maxima?

I came up with this nice thing, which I am calling 'partition function for symmetric groups'
Z[0]:1;
Z[n]:=expand(sum((n-1)!/i!*z[n-i]*Z[i], i, 0, n-1));
Z[4];
6*z[4]+8*z[1]*z[3]+3*z[2]^2+6*z[1]^2*z[2]+z[1]^4
The sum of the coefficients for Z[4] is 6+8+3+6+1 = 24 = 4!
which I am hoping corresponds to the fact that the group S4 has 6 elements like (abcd), 8 like (a)(bcd), 3 like (ab)(cd), 6 like (a)(b)(cd), and 1 like (a)(b)(c)(d)
So I thought to myself, the sum of the coefficients of Z[20] should be 20!
But life being somewhat on the short side, and fingers giving trouble, I was hoping to confirm this automatically. Can anyone help?
This sort of thing points a way:
Z[20],z[1]=1,z[2]=1,z[3]=1,z[4]=1,z[5]=1,z[6]=1,z[7]=1,z[8]=1;
But really...
I don't know a straightforward way to do that; coeff seems to handle only a single variable at a time. But here's a way to get the list you want. The basic idea is to extract the terms of Z[20] as a list, and then evaluate each term with z[1] = 1, z[2] = 1, ..., z[20] = 1.
(%i1) display2d : false $
(%i2) Z[0] : 1 $
(%i3) Z[n] := expand (sum ((n - 1)!/i!*z[n - i]*Z[i], i, 0, n-1)) $
(%i4) z1 : makelist (z[i] = 1, i, 1, 20);
(%o4) [z[1] = 1,z[2] = 1,z[3] = 1,z[4] = 1,z[5] = 1,z[6] = 1,z[7] = 1, ...]
(%i5) a : args (Z[20]);
(%o5) [121645100408832000*z[20],128047474114560000*z[1]*z[19],
67580611338240000*z[2]*z[18],67580611338240000*z[1]^2*z[18],
47703960944640000*z[3]*z[17],71555941416960000*z[1]*z[2]*z[17], ...]
(%i6) a1 : ev (a, z1);
(%o6) [121645100408832000,128047474114560000,67580611338240000, ...]
(%i7) apply ("+", a1);
(%o7) 2432902008176640000
(%i8) 20!;
(%o8) 2432902008176640000