How to build lazy lists with defined generators and is there a "takeWhile" alternative? - raku

I am reading through perl6intro on lazy lists and it leaves me confused about certain things.
Take this example:
sub foo($x) {
$x**2
}
my $alist = (1,2, &foo ... ^ * > 100);
will give me (1 2 4 16 256), it will square the same number until it exceeds 100. I want this to give me (1 4 9 16 25 .. ), so instead of squaring the same number, to advance a number x by 1 (or another given "step"), foo x, and so on.
Is it possible to achieve this in this specific case?
Another question I have on lazy lists is the following:
In Haskell, there is a takeWhile function, does something similar exist in Perl6?

I want this to give me (1 4 9 16 25 .. )
The easiest way to get that sequence, would be:
my #a = (1..*).map(* ** 2); # using a Whatever-expression
my #a = (1..*).map(&foo); # using your `foo` function
...or if you prefer to write it in a way that resembles a Haskell/Python list comprehension:
my #a = ($_ ** 2 for 1..*); # using an in-line expression
my #a = (foo $_ for 1..*); # using your `foo` function
While it is possible to go out of one's way to express this sequence via the ... operator (as Brad Gilbert's answer and raiph's answer demonstrate), it doesn't really make sense, as the purpose of that operator is to generate sequences where each element is derived from the previous element(s) using a consistent rule.
Use the best tool for each job:
If a sequence is easiest to express iteratively (e.g. Fibonacci sequence):
Use the ... operator.
If a sequence is easiest to express as a closed formula (e.g. sequence of squares):
Use map or for.

Here is how you could write a Perl 6 equivalent of Haskell's takewhile.
sub take-while ( &condition, Iterable \sequence ){
my \iterator = sequence.iterator;
my \generator = gather loop {
my \value = iterator.pull-one;
last if value =:= IterationEnd or !condition(value);
take value;
}
# should propagate the laziness of the sequence
sequence.is-lazy
?? generator.lazy
!! generator
}
I should probably also show an implementation of dropwhile.
sub drop-while ( &condition, Iterable \sequence ){
my \iterator = sequence.iterator;
GATHER: my \generator = gather {
# drop initial values
loop {
my \value = iterator.pull-one;
# if the iterator is out of values, stop everything
last GATHER if value =:= IterationEnd;
unless condition(value) {
# need to take this so it doesn't get lost
take value;
# continue onto next loop
last;
}
}
# take everything else
loop {
my \value = iterator.pull-one;
last if value =:= IterationEnd;
take value
}
}
sequence.is-lazy
?? generator.lazy
!! generator
}
These are only just-get-it-working examples.
It could be argued that these are worth adding as methods to lists/iterables.
You could (but probably shouldn't) implement these with the sequence generator syntax.
sub take-while ( &condition, Iterable \sequence ){
my \iterator = sequence.iterator;
my \generator = { iterator.pull-one } …^ { !condition $_ }
sequence.is-lazy ?? generator.lazy !! generator
}
sub drop-while ( &condition, Iterable \sequence ){
my \end-condition = sequence.is-lazy ?? * !! { False };
my \iterator = sequence.iterator;
my $first;
loop {
$first := iterator.pull-one;
last if $first =:= IterationEnd;
last unless condition($first);
}
# I could have shoved the loop above into a do block
# and placed it where 「$first」 is below
$first, { iterator.pull-one } … end-condition
}
If they were added to Perl 6/Rakudo, they would likely be implemented with Iterator classes.
( I might just go and add them. )
A direct implementation of what you are asking for is something like:
do {
my $x = 0;
{ (++$x)² } …^ * > 100
}
Which can be done with state variables:
{ ( ++(state $x = 0) )² } …^ * > 100
And a state variable that isn't used outside of declaring it doesn't need a name.
( A scalar variable starts out as an undefined Any, which becomes 0 in a numeric context )
{ (++( $ ))² } …^ * > 100
{ (++$)² } …^ * > 100
If you need to initialize the anonymous state variable, you can use the defined-or operator // combined with the equal meta-operator =.
{ (++( $ //= 5))² } …^ * > 100
In some simple cases you don't have to tell the sequence generator how to calculate the next values.
In such cases the ending condition can also be simplified.
say 1,2,4 ...^ 100
# (1 2 4 8 16 32 64)
The only other time you can safely simplify the ending condition is if you know that it will stop on the value.
say 1, { $_ * 2 } ... 64;
# (1 2 4 8 16 32 64)
say 1, { $_ * 2 } ... 3;
# (1 2 4 8 16 32 64 128 256 512 ...)

I want this to give me (1 4 9 16 25 .. )
my #alist = {(++$)²} ... Inf;
say #alist[^10]; # (1 4 9 16 25 36 49 64 81 100)
The {…} is an arbitrary block of code. It is invoked for each value of a sequence when used as the LHS of the ... sequence operator.
The (…)² evaluates to the square of the expression inside the parens. (I could have written (…) ** 2 to mean the same thing.)
The ++$ returns 1, 2, 3, 4, 5, 6 … by combining a pre-increment ++ (add one) with a $ variable.
In Haskell, there is a takeWhile function, does something similar exist in Perl6?
Replace the Inf from the above sequence with the desired end condition:
my #alist = {(++$)²} ... * > 70; # stop at step that goes past 70
say #alist; # [1 4 9 16 25 36 49 64 81]
my #alist = {(++$)²} ...^ * > 70; # stop at step before step past 70
say #alist; # [1 4 9 16 25 36 49 64]
Note how the ... and ...^ variants of the sequence operator provide the two variations on the stop condition. I note in your original question you have ... ^ * > 70, not ...^ * > 70. Because the ^ in the latter is detached from the ... it has a different meaning. See Brad's comment.

Related

Kotlin. Function does not exit recursion after return

I need to decompose the number l into prime factors. For this I use recursion. And when l = 1, the function must exit their recursion and return the string in which the prime factors are located, however, the function continues to work and already according to a principle incomprehensible to me. Please explain what is the problem with my code?
fun factors(l: Int): String {
return if (l == 1) {
answer
} else {
for (i in 2..l) {
if (l % i == 0) {
answer += "$i "
factors(l / i)
}
}
return factors(l)
}
}
Let's first mention some issues in your current code:
You're mixing semantics, here. What is the contract of your function? Does it return a value, or does it modify a global variable? Pick one, don't do both.
You should not use a global variable because it's way harder to follow. Instead, construct your values locally from the current information + whatever the recursive call returns to you
You're already using an if expression with the syntax return if (condition) { ... } else { ... }. This means each branch of the if should just end with an expression, you don't need to use return again. That said, in this case the first branch is rather a special case that you want to get out of the way before doing the bulk of the general work. In this kind of situation, I would rather use a statement like if (condition) { return X } at the beginning and then have the rest of the body of the function unnested, instead of using an if expression (but that is a personal preference).
It is strange to compute the list of factors as a string. You likely want to avoid duplicates and maybe sort them, so a List<Int> or a Set<Int> would likely be more appropriate. You can always format after the fact using things like joinToString(" ")
I'm not sure I get the math correctly, but it seems you really will be getting all factors here, not just the prime factors.
Now, the actual cause of the behaviour you're seeing is that you're calling your function recursively with the same number at the end: return factors(l). This means that calling factors(l) with any l > 1 will end up calling itself with the same value over and over. Recursive calls need to change some arguments to the function if you don't want it to be infinite.
fun factors(value: Int, list: MutableList<Int> = mutableListOf()): MutableList<Int> {
if (value > 1) {
for (i in 2..value) {
if (value % i == 0) {
list.add(i)
list.addAll(factors(value / i))
break
}
}
}
return list
}
(2..25).forEach {
val factors = factors(it)
val result = factors.reduce { acc, i -> acc * i }.toString() + " = " + factors.joinToString(" × ")
println(result)
}
Edit: this version is based on #Joffrey's comment below. Plus I decided to wrap the recursive function, now called fn, into a function in order to have a clean parameter list for factors():
fun factors(value: Int): List<Int> {
fun fn(value: Int, list: MutableList<Int>) {
if (value > 1) {
for (i in 2..value) {
if (value % i == 0) {
list.add(i)
fn(value / i, list)
break
}
}
}
}
val list = mutableListOf<Int>()
fn(value, list)
return list
}
Output:
2 = 2
3 = 3
4 = 2 × 2
5 = 5
6 = 2 × 3
7 = 7
8 = 2 × 2 × 2
9 = 3 × 3
10 = 2 × 5
11 = 11
12 = 2 × 2 × 3
13 = 13
14 = 2 × 7
15 = 3 × 5
16 = 2 × 2 × 2 × 2
17 = 17
18 = 2 × 3 × 3
19 = 19
20 = 2 × 2 × 5
21 = 3 × 7
22 = 2 × 11
23 = 23
24 = 2 × 2 × 2 × 3
25 = 5 × 5

Rational numbers in Raku

I am using Raku for some computations, because it has nice numeric types. However, I have an issue with using '.raku'
say (1/6+1/6).raku
#<1/3>
We obtain this. However,
say (1/10+1/10).raku
#0.2
Is it a bug? I expected <1/5>. What happens?
In Raku, 0.2 constructs a Rat, and thus produces the very same result as writing 1/5 (which will be constant folded) or <1/5> (the literal form). You only get floating point in the case of specifying an exponent (for example, 2e-1).
The .raku (formerly known as the .perl) method's job is to produce something that will roundtrip and produce the same value if EVAL'd. In the case of 1/5, that can be exactly represented as a decimal, so it will produce 0.2. It only resorts to the fractional representation when a decimal form would not round-trip.
You can always recover the numerator and denominator using the .numerator and .denominator methods to format as you wish. Additionally .nude method returns a list of the numerator and denominator, which one can join with a / if wanted:
say (1/6+1/6).nude.join("/"); # 1/3
say (1/10+1/10).nude.join("/"); # 1/5
Hi #milou123 I was also a bit surprised that raku reverts to decimal representation - I can see that some contexts - such as teaching fractional arithmetic would benefit from having a "keep as rat" mode. Having said that, ultimately it makes sense that there is only one way to .raku something and that decimal is the default representation.
Of course, with raku, you can also just change the language a bit. In this case, I have invented a new '→' postfix operator...
multi postfix:<→> ( Rat:D $r ) { $r.nude.join("/") }
say (1/5+1/5)→; # 2/5
I am not smart enough to work out if the built in 'raku' method can be overridden in a similar way, would be keen to see advice on how to do that concisely...
try this in Julia:
julia> 1 // 10 + 1 // 10
1//5
julia> typeof(1 // 10 + 1 // 10)
Rational{Int64}
julia> 1 // 2 + 1 // 3
5//6
julia> typeof(1 // 2 + 1 // 3)
Rational{Int64}
in the Rat.pm6 implemention, we can only call .raku method on Rat type to get the expected format:
multi method raku(Rat:D: --> Str:D) {
if $!denominator == 1 {
$!numerator ~ '.0'
}
else {
my $d = $!denominator;
unless $d == 0 {
$d = $d div 5 while $d %% 5;
$d = $d div 2 while $d %% 2;
}
if $d == 1 and (my $b := self.base(10,*)).Numeric === self {
$b;
}
else {
'<' ~ $!numerator ~ '/' ~ $!denominator ~ '>'
}
}
}

Why does `variable++` increment the variable but `variable + 1` does not?

Here's the problem in which I encountered this issue:
The function should compare the value at each index position and score a point if the value for that position is higher. No point if they are the same. Given a = [1, 1, 1] b = [1, 0, 0] output should be [2, 0]
fun compareArrays(a: Array<Int>, b: Array<Int>): Array<Int> {
var aRetVal:Int = 0
var bRetVal:Int = 0
for(i in 0..2){
when {
a[i] > b[i] -> aRetVal + 1 // This does not add 1 to the variable
b[i] > a[i] -> bRetVal++ // This does...
}
}
return arrayOf(aRetVal, bRetVal)
}
The IDE even says that aRetVal is unmodified and should be declared as a val
What others said is true, but in Kotlin there's more. ++ is just syntactic sugar and under the hood it will call inc() on that variable. The same applies to --, which causes dec() to be invoked (see documentation). In other words a++ is equivalent to a.inc() (for Int or other primitive types that gets optimised by the compiler and increment happens without any method call) followed by a reassignment of a to the incremented value.
As a bonus, consider the following code:
fun main() {
var i = 0
val x = when {
i < 5 -> i++
else -> -1
}
println(x) // prints 0
println(i) // prints 1
val y = when {
i < 5 -> ++i
else -> -1
}
println(y) // prints 2
println(i) // prints 2
}
The explanation for that comes from the documentation I linked above:
The compiler performs the following steps for resolution of an operator in the postfix form, e.g. a++:
Store the initial value of a to a temporary storage a0;
Assign the result of a.inc() to a;
Return a0 as a result of the expression.
...
For the prefix forms ++a and --a resolution works the same way, and the effect is:
Assign the result of a.inc() to a;
Return the new value of a as a result of the expression.
Because
variable++ is shortcut for variable = variable + 1 (i.e. with assignment)
and
variable + 1 is "shortcut" for variable + 1 (i.e. without assignment, and actually not a shortcut at all).
That is because what notation a++ does is actually a=a+1, not just a+1. As you can see, a+1 will return a value that is bigger by one than a, but not overwrite a itself.
Hope this helps. Cheers!
The equivalent to a++ is a = a + 1, you have to do a reassignment which the inc operator does as well.
This is not related to Kotlin but a thing you'll find in pretty much any other language

Perl 6 to show index while looping through a list

When looping through a list (or an array), is there a way to know the index of the current element inside the loop?
Of course, the problem can be solved by looping through indices:
my #aa = 8 .. 12;
say "$_\t#aa[$_]" for 0 ..^ #aa.elems;
But maybe something like the following is possible (I marked with .CURRENT_INDEX the method I'm looking for)?
my #aa = 8 .. 12;
say $_.CURRENT_INDEX\t$_ for #aa;
To get the loop index of the current element of loop over a list, you can use the .kv method of a list. It returns an interleaved sequence of indexes and values:
my #aa = 8 .. 12;
for #aa.kv -> $i, $_ { say "$i: $_" }
Output:
0: 8
1: 9
2: 10
3: 11
4: 12
TLDR: Use .kv or .pairs.
This is sort of what is really happening under the hood:
my #aa = 8 .. 12;
my \iterator = #aa.iterator;
while ($_ := iterator.pull-one) !=:= IterationEnd {
say $_
}
The value in iterator in this case is an anonymous class that does the Iterator role.
An Iterator may or may not have any way to know how many values it has produced. For example the Iterator for .roll(*) doesn't need to know how many values it has produced so far, so it doesn't.
It is possible for an Iterator to implement a method that returns its current index.
my #aa = 8 .. 12;
my \iterator = class :: does Iterator {
has $.index = 0; # declares it as public (creates a method)
has #.values;
method pull-one () {
return IterationEnd unless #!values;
++$!index; # this is not needed in most uses of an Iterator
shift #!values;
}
}.new( values => #aa );
say "{iterator.index}\t$_" for Seq.new: iterator;
1 8
2 9
3 10
4 11
5 12
You could also do it in a higher level construct;
my #aa = 8 .. 12;
my $index = 0;
my $seq := gather for #aa { ++$index; take $_ };
say "$index\t$_" for $seq;
To get $_.CURRENT-INDEX to work requires wrapping the result.
class Iterator-Indexer does Iterator {
has Iterator $.iterator is required;
has $!index = 0;
method pull-one () {
my \current-value = $!iterator.pull-one;
# make sure it ends properly
return IterationEnd if current-value =:= IterationEnd;
# element wrapper class
class :: {
has $.CURRENT-INDEX;
has $.value;
# should have a lot more coercion methods to work properly
method Str () { $!value }
}.new( CURRENT-INDEX => $!index++, value => current-value )
}
}
multi sub with-index ( Iterator \iter ){
Seq.new: Iterator-Indexer.new: iterator => iter;
}
multi sub with-index ( Iterable \iter ){
Seq.new: Iterator-Indexer.new: iterator => iter.iterator;
}
my #aa = 8 .. 12;
say "$_.CURRENT-INDEX()\t$_" for with-index #aa.iterator;
# note that $_ is an instance of the anonymous wrapper class
Again with a higher level construct:
my #aa = 8 .. 12;
my \sequence := #aa.kv.map: -> $index, $_ {
# note that this doesn't close over the current value in $index
$_ but role { method CURRENT-INDEX () { $index }}
}
say "$_.CURRENT-INDEX()\t$_" for sequence;
I would argue that you should just use .pairs if you want it something like this. (or use .kv but that basically requires using the block form of for with two parameters)
my #aa = 8 .. 12;
say "$_.key()\t$_.value()" for #aa.pairs;
Here's another way, using your own index variable:
my #aa = 8..12;
say $++, ": $_" for #aa;
Output:
0: 8
1: 9
2: 10
3: 11
4: 12

Conditionally return empty iterator from flat_map

Given this definition for foo:
let foo = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
I'd like to be able to write code like this:
let result: Vec<_> = foo.iter()
.enumerate()
.flat_map(|(i, row)| if i % 2 == 0 {
row.iter().map(|x| x * 2)
} else {
std::iter::empty()
})
.collect();
but that raises an error about the if and else clauses having incompatible types. I tried removing the map temporarily and I tried defining an empty vector outside the closure and returning an iterator over that like so:
let empty = vec![];
let result: Vec<_> = foo.iter()
.enumerate()
.flat_map(|(i, row)| if i % 2 == 0 {
row.iter() //.map(|x| x * 2)
} else {
empty.iter()
})
.collect();
This seems kind of silly but it compiles. If I try to uncomment the map then it still complains about the if and else clauses having incompatible types. Here's part of the error message:
error[E0308]: if and else have incompatible types
--> src/main.rs:6:30
|
6 | .flat_map(|(i, row)| if i % 2 == 0 {
| ______________________________^
7 | | row.iter().map(|x| x * 2)
8 | | } else {
9 | | std::iter::empty()
10 | | })
| |_________^ expected struct `std::iter::Map`, found struct `std::iter::Empty`
|
= note: expected type `std::iter::Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:7:28: 7:37]>`
found type `std::iter::Empty<_>`
Playground Link
I know I could write something that does what I want with some nested for loops but I'd like to know if there's a terse way to write it using iterators.
Since Rust is statically typed and each step in an iterator chain changes the result to a new type that entrains the previous types (unless you use boxed trait objects) you will have to write it in a way where both branches are covered by the same types.
One way to convey conditional emptiness with a single type is the TakeWhile iterator implementation.
.flat_map(|(i, row)| {
let iter = row.iter().map(|x| x * 2);
let take = i % 2 == 0;
iter.take_while(|_| take)
})
If you don't mind ignoring the edge-case where the input iterator foo could have more than usize elements you could also use Take instead with either 0 or usize::MAX. It has the advantage of providing a better size_hint() than TakeWhile.
In your specific example, you can use filter to remove unwanted elements prior to calling flat_map:
let result: Vec<_> = foo.iter()
.enumerate()
.filter(|&(i, _)| i % 2 == 0)
.flat_map(|(_, row)| row.iter().map(|x| x * 2))
.collect();
If you ever want to use it with map instead of flat_map, you can combine the calls to filter and map by using filter_map which takes a function returning an Option and only keeps elements that are Some(thing).