how to pass a class method as argument to another method of the class in perl 6 - raku

I have a script like the below. Intent is to have different filter methods to filter a list.
Here is the code.
2
3 class list_filter {
4 has #.my_list = (1..20);
5
6 method filter($l) { return True; }
7
8 # filter method
9 method filter_lt_10($l) {
10 if ($l > 10) { return False; }
11 return True;
12 }
13
14 # filter method
15 method filter_gt_10($l) {
16 if ($l < 10) { return False; }
17 return True;
18 }
19
20 # expecting a list of (1..10) to be the output here
21 method get_filtered_list_lt_10() {
22 return self.get_filtered_list(&{self.filter_lt_10});
23 }
24
25 # private
26 method get_filtered_list(&filter_method) {
27 my #newlist = ();
28 for #.my_list -> $l {
29 if (&filter_method($l)) { push(#newlist, $l); }
30 }
31 return #newlist;
32 }
33 }
34
35 my $listobj = list_filter.new();
36
37 my #outlist = $listobj.get_filtered_list_lt_10();
38 say #outlist;
Expecting [1..10] to be the output here. But getting following error.
Too few positionals passed; expected 2 arguments but got 1
in method filter_lt_10 at ./b.pl6 line 9
in method get_filtered_list_lt_10 at ./b.pl6 line 22
in block <unit> at ./b.pl6 line 37
What am I doing wrong here?

Passing a method as a parameter in Perl 6 either requires you to use MOP (Meta-Object Protocol) methods, or pass the method by name (which would then do the lookup for you at runtime).
But why use methods if you're not really doing something with the object in those methods? They might as well be subs then, which you can pass as a parameter.
Perhaps this is best by example:
class list_filter {
has #.my_list = 1..20; # don't need parentheses
sub filter($ --> True) { } # don't need code, signature is enough
# filter sub
sub filter_lt_10($l) { not $l > 10 }
# filter sub
sub filter_gt_10($l) { not $l < 10 }
# private
method !get_filtered_list(&filter_sub) {
#.my_list.grep(&filter_sub);
}
# expecting a list of (1..10) to be the output here
method get_filtered_list_lt_10() {
self!get_filtered_list(&filter_lt_10);
}
}
my $listobj = list_filter.new();
my #outlist = $listobj.get_filtered_list_lt_10();
say #outlist; # [1 2 3 4 5 6 7 8 9 10]
The first sub filter, which only returns a constant value (in this case True), can be represented much more easily in the signature with an empty body.
The filter_lt_10 and filter_gt_10 subs only need the condition negated, hence the use of the not.
The get_filtered_list method is supposed to be private, so make it a private method by prefixing !.
In the get_filtered_list_lt_10 you now need to call get_filtered_list with a ! instead of a .. And you pass the filter_lt_10 sub as a parameter by prefixing the & (otherwise it would be considered a call to the sub without any parameters, which would fail).
Change the get_filtered_listto use the built-in grep method: this takes a Callable block that takes a single parameter and which should return something True to include the value of the list it works upon. Since a sub taking a single parameter is a Callable, we can just specify the sub there directly.
Hope this made sense. I tried to stay as close as possible to the intended semantics.
Some general programming remarks: it feels to me that the naming of the subs is confusing: it feels to me that they should be called filter_le_10 and filter_ge_10, because that's really what they do it appears to me. Also, if you really don't want any ad-hoc filtering, but only filtering from a specific set of predefined filters, you would probably be better of by creating a dispatch table using constants or enums, and use that to indicate which filter you want, rather than encoding this information in the name of yet another method to make and maintain.
Hope this helps.

TL;DR You told P6 what arguments to expect when calling your filter method. Then you failed to pass the agreed argument(s) when you called it. So P6 complained on your behalf. To resolve the issue, either pass the argument(s) you told P6 to expect or stop telling P6 to expect them. :)
The message says expected 2, got 1, rather than expected 1 got 0.
This is because self is implicitly passed and added to the "expected" and "got" totals in this appended bit of message detail, bumping both up by one. (This detail is perhaps Less Than Awesome, i.e. something we should perhaps consider fixing.)
When I run your code on tio I get:
Too few positionals passed; expected 2 arguments but got 1
in method filter at .code.tio line 27
in method print_filtered_list at .code.tio line 12
in block <unit> at .code.tio line 42
The method declaration method filter($l) {...} at line 27 tells P6 to expect two arguments for each .filter method call:
The invocant. (This will be bound to self.) Let's call that argument A.
A positional argument. (This will be bound to the $l parameter). Let's call that argument B.
But in &{self.filter} in line 12, while you provide the .filter method call with an argument A, i.e. an invocant argument, you don't provide an argument B, i.e. a positional argument (after filter, e.g. &{self.filter(42)}).
Hence Too few positionals passed; expected 2 arguments but got 1.

The &{self.method} syntax was new to me, so thanks for that. Unfortunately it doesn't work if parameters are needed. You can use sub as other posters mentioned, but if you need to use methods, you can get a method by calling self.^lookup, which is the use of the meta-object protocol that Elizabeth mentioned. ('^' means you're not calling a method that's part of that class, but rather part of the "shadow" class which contains the main class's guts / implementation details.)
To get a method, use run obj.^lookup(method name), and call it by passing in the object itself (often "self") as the first parameter, then the other parameters. To bind the object to the function so it doesn't need to be explicitly added each time, use the assuming function.
class MyClass {
method log(Str $message) { say now ~ " $message"; }
method get-logger() { return self.^lookup('log').assuming(self); }
}
my &log = MyClass.get-logger();
log('hello'); # output: Instant:1515047449.201730 hello

Found it. this is what worked for me.
3 class list_filter {
4 has #.my_list = (1..20);
5
6 # will be overriding this in derived classes
7 method filter1($l) { return True; }
8 method filter2($l) { return True; }
9
10 # same print method I will be calling from all derived class objects
11 method print_filtered_list($type) {
12 my #outlist = self.get_filtered_list($type);
13 say #outlist;
14 }
15
16 # private
17 method get_filtered_list($type) {
18 my #newlist = ();
19 for #.my_list -> $l {
20 my $f = "filter$type";
21 if (self."$f"($l)) { push(#newlist, $l); }
22 }
23 return #newlist;
24 }
25 }
26
27 class list_filter_lt_10 is list_filter {
28 method filter1($l) {
29 if ($l > 10) { return False; }
30 return True;
31 }
32 method filter2($l) {
33 if ($l > 10) { return False; }
34 if ($l < 5) { return False; }
35 return True;
36 }
37 }
38
39 class list_filter_gt_10 is list_filter {
40 method filter1($l) {
41 if ($l < 10) { return False; }
42 return True;
43 }
44 method filter2($l) {
45 if ($l < 10) { return False; }
46 if ($l > 15) { return False; }
47 return True;
48 }
49 }
50
51 my $listobj1 = list_filter_lt_10.new();
52 $listobj1.print_filtered_list(1);
53 $listobj1.print_filtered_list(2);
54
55 my $listobj2 = list_filter_gt_10.new();
56 $listobj2.print_filtered_list(1);
57 $listobj2.print_filtered_list(2);
58
Output:
./b.pl6
[1 2 3 4 5 6 7 8 9 10]
[5 6 7 8 9 10]
[10 11 12 13 14 15 16 17 18 19 20]
[10 11 12 13 14 15]

piojo's answer looks like it would work (though I haven't tried it).
Another approach to turning a method into a variable is to use indirection:
class Foo {
method bar($a) {
$a * 2
}
}
sub twice(&f, $x) {
f f $x
}
my $foo = Foo.new();
say twice {$foo.bar: $^a}, 1

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

Razorpay integration error (not enough arguments in call to client.Order.Create)

Tried to implement, based on the official documentation in razorpay site
Code :
11 func indexpageGet(c *gin.Context) {
12
13 client := razorpay.NewClient("rzp_test_zlsYshjhjhjln", "9LtUy4qhghghgh2asp59es")
14
15 data := map[string]interface{}{
16 "amount": 1234,
17 "currency": "INR",
18 "receipt_id": "some_receipt_id",
19 }
20 body, err := client.Order.Create(data)
21 if err != nil {
22 fmt.Println(err)
23 }
24
25 fmt.Println(body)
Compile Error:
./main.go:20:34: not enough arguments in call to client.Order.Create
have (map[string]interface {})
want (map[string]interface {}, map[string]string)
My Observation: function client.Order.Create(data) required two arguments I confirmed it from razorpay library (see the function definition part). So the solution is I need to pass second argument (extraHeaders) too.
// Create creates a new order for the given data
func (order *Order) Create(data map[string]interface{}, extraHeaders map[string]string) (map[string]interface{}, error) {
return order.Request.Post(constants.ORDER_URL, data, extraHeaders)
}
The point I am stuck is what is extraHeaders and what value I need to pass?
based on the comments in the Question, Made 2 things to made it work : (Refer the comments in below code )
11 func indexpageGet(c *gin.Context) {
12
13 client := razorpay.NewClient("rzp_test_zlsYsrvuUxxhln", "9LtUy4qpLCOtl4Gz2asp59es")
14
15 data := map[string]interface{}{
16 "amount": 1234,
17 "currency": "INR",
18 "receipt": "110",
19 //"receipt_id": "some_receipt_id", // 1st Mistake in documentation it should be 'receipt', corrected in above line
20 }
21
22 extraHeader := make(map[string]string) // 2nd Mistake in documentation , corrected by creating an empty map and passed as the second argument in below function.
23 body, err := client.Order.Create(data,extraHeader)
24 if err != nil {
25 fmt.Println(err)
26 }
27
28 fmt.Println(body)
The documentation says that create functions takes two arguments one as map[string]interface{} and the other as extraHeaders which is map[string]string.
You can set the extraHeaders parameter to nil and your code will work.

Perl6 Using Proxy to trigger on attribute access

I am trying to implement a trigger on write access to a perl6 Class attribute. I cannot figure out the cause of the error...
... I got this notion from How does one write custom accessor methods in Perl6?
1 #!/usr/bin/env perl6
2
3 class MeasureSP {
4
5 has Real $!value;
6 has Str $.units;
7
8 submethod BUILD( :$!value, :$!units ) {}
9
10 method value( Real $newval? ) is rw {
11 return Proxy.new:
12 FETCH => sub ($) { $!value },
13 STORE => sub ($, $newval) { $!value = $newval },
14 }
15
16 }
17 my MeasureSP $m-sp = MeasureSP.new( value => 23, units => 'metres' );
18 say $m-sp.units; #metres
19 say $m-sp.value; #23
20 $m-sp.value = 1;
21 # Cannot assign to a readonly variable or a value
22 #in block <unit> at ./retry.p6 line 20
This behaviour seems to have changed - this code was working fine back in June 18 - but I want to be sure I am in step with the latest thinking.
Any help would be very much appreciated !
Either remove the return:
method value( Real $newval? ) is rw {
Proxy.new:
FETCH => sub ($) { $!value },
STORE => sub ($, $newval) { $!value = $newval },
}
Or use return-rw if you really want to be explicit:
method value( Real $newval? ) is rw {
return-rw Proxy.new:
FETCH => sub ($) { $!value },
STORE => sub ($, $newval) { $!value = $newval },
}
The problem is that return will strip away any item container, so just putting is rw on the method is not enough on its own.
As to why the posted code used to work, but no longer does: Rakudo releases in the last couple of months have included a fix for a bug that meant Proxy was treated differently than Scalar in routine return handling. The Proxy was not stripped in places it should have been; now it reliably is.

perl 6 passing methods as arguments [duplicate]

I have a script like the below. Intent is to have different filter methods to filter a list.
Here is the code.
2
3 class list_filter {
4 has #.my_list = (1..20);
5
6 method filter($l) { return True; }
7
8 # filter method
9 method filter_lt_10($l) {
10 if ($l > 10) { return False; }
11 return True;
12 }
13
14 # filter method
15 method filter_gt_10($l) {
16 if ($l < 10) { return False; }
17 return True;
18 }
19
20 # expecting a list of (1..10) to be the output here
21 method get_filtered_list_lt_10() {
22 return self.get_filtered_list(&{self.filter_lt_10});
23 }
24
25 # private
26 method get_filtered_list(&filter_method) {
27 my #newlist = ();
28 for #.my_list -> $l {
29 if (&filter_method($l)) { push(#newlist, $l); }
30 }
31 return #newlist;
32 }
33 }
34
35 my $listobj = list_filter.new();
36
37 my #outlist = $listobj.get_filtered_list_lt_10();
38 say #outlist;
Expecting [1..10] to be the output here. But getting following error.
Too few positionals passed; expected 2 arguments but got 1
in method filter_lt_10 at ./b.pl6 line 9
in method get_filtered_list_lt_10 at ./b.pl6 line 22
in block <unit> at ./b.pl6 line 37
What am I doing wrong here?
Passing a method as a parameter in Perl 6 either requires you to use MOP (Meta-Object Protocol) methods, or pass the method by name (which would then do the lookup for you at runtime).
But why use methods if you're not really doing something with the object in those methods? They might as well be subs then, which you can pass as a parameter.
Perhaps this is best by example:
class list_filter {
has #.my_list = 1..20; # don't need parentheses
sub filter($ --> True) { } # don't need code, signature is enough
# filter sub
sub filter_lt_10($l) { not $l > 10 }
# filter sub
sub filter_gt_10($l) { not $l < 10 }
# private
method !get_filtered_list(&filter_sub) {
#.my_list.grep(&filter_sub);
}
# expecting a list of (1..10) to be the output here
method get_filtered_list_lt_10() {
self!get_filtered_list(&filter_lt_10);
}
}
my $listobj = list_filter.new();
my #outlist = $listobj.get_filtered_list_lt_10();
say #outlist; # [1 2 3 4 5 6 7 8 9 10]
The first sub filter, which only returns a constant value (in this case True), can be represented much more easily in the signature with an empty body.
The filter_lt_10 and filter_gt_10 subs only need the condition negated, hence the use of the not.
The get_filtered_list method is supposed to be private, so make it a private method by prefixing !.
In the get_filtered_list_lt_10 you now need to call get_filtered_list with a ! instead of a .. And you pass the filter_lt_10 sub as a parameter by prefixing the & (otherwise it would be considered a call to the sub without any parameters, which would fail).
Change the get_filtered_listto use the built-in grep method: this takes a Callable block that takes a single parameter and which should return something True to include the value of the list it works upon. Since a sub taking a single parameter is a Callable, we can just specify the sub there directly.
Hope this made sense. I tried to stay as close as possible to the intended semantics.
Some general programming remarks: it feels to me that the naming of the subs is confusing: it feels to me that they should be called filter_le_10 and filter_ge_10, because that's really what they do it appears to me. Also, if you really don't want any ad-hoc filtering, but only filtering from a specific set of predefined filters, you would probably be better of by creating a dispatch table using constants or enums, and use that to indicate which filter you want, rather than encoding this information in the name of yet another method to make and maintain.
Hope this helps.
TL;DR You told P6 what arguments to expect when calling your filter method. Then you failed to pass the agreed argument(s) when you called it. So P6 complained on your behalf. To resolve the issue, either pass the argument(s) you told P6 to expect or stop telling P6 to expect them. :)
The message says expected 2, got 1, rather than expected 1 got 0.
This is because self is implicitly passed and added to the "expected" and "got" totals in this appended bit of message detail, bumping both up by one. (This detail is perhaps Less Than Awesome, i.e. something we should perhaps consider fixing.)
When I run your code on tio I get:
Too few positionals passed; expected 2 arguments but got 1
in method filter at .code.tio line 27
in method print_filtered_list at .code.tio line 12
in block <unit> at .code.tio line 42
The method declaration method filter($l) {...} at line 27 tells P6 to expect two arguments for each .filter method call:
The invocant. (This will be bound to self.) Let's call that argument A.
A positional argument. (This will be bound to the $l parameter). Let's call that argument B.
But in &{self.filter} in line 12, while you provide the .filter method call with an argument A, i.e. an invocant argument, you don't provide an argument B, i.e. a positional argument (after filter, e.g. &{self.filter(42)}).
Hence Too few positionals passed; expected 2 arguments but got 1.
The &{self.method} syntax was new to me, so thanks for that. Unfortunately it doesn't work if parameters are needed. You can use sub as other posters mentioned, but if you need to use methods, you can get a method by calling self.^lookup, which is the use of the meta-object protocol that Elizabeth mentioned. ('^' means you're not calling a method that's part of that class, but rather part of the "shadow" class which contains the main class's guts / implementation details.)
To get a method, use run obj.^lookup(method name), and call it by passing in the object itself (often "self") as the first parameter, then the other parameters. To bind the object to the function so it doesn't need to be explicitly added each time, use the assuming function.
class MyClass {
method log(Str $message) { say now ~ " $message"; }
method get-logger() { return self.^lookup('log').assuming(self); }
}
my &log = MyClass.get-logger();
log('hello'); # output: Instant:1515047449.201730 hello
Found it. this is what worked for me.
3 class list_filter {
4 has #.my_list = (1..20);
5
6 # will be overriding this in derived classes
7 method filter1($l) { return True; }
8 method filter2($l) { return True; }
9
10 # same print method I will be calling from all derived class objects
11 method print_filtered_list($type) {
12 my #outlist = self.get_filtered_list($type);
13 say #outlist;
14 }
15
16 # private
17 method get_filtered_list($type) {
18 my #newlist = ();
19 for #.my_list -> $l {
20 my $f = "filter$type";
21 if (self."$f"($l)) { push(#newlist, $l); }
22 }
23 return #newlist;
24 }
25 }
26
27 class list_filter_lt_10 is list_filter {
28 method filter1($l) {
29 if ($l > 10) { return False; }
30 return True;
31 }
32 method filter2($l) {
33 if ($l > 10) { return False; }
34 if ($l < 5) { return False; }
35 return True;
36 }
37 }
38
39 class list_filter_gt_10 is list_filter {
40 method filter1($l) {
41 if ($l < 10) { return False; }
42 return True;
43 }
44 method filter2($l) {
45 if ($l < 10) { return False; }
46 if ($l > 15) { return False; }
47 return True;
48 }
49 }
50
51 my $listobj1 = list_filter_lt_10.new();
52 $listobj1.print_filtered_list(1);
53 $listobj1.print_filtered_list(2);
54
55 my $listobj2 = list_filter_gt_10.new();
56 $listobj2.print_filtered_list(1);
57 $listobj2.print_filtered_list(2);
58
Output:
./b.pl6
[1 2 3 4 5 6 7 8 9 10]
[5 6 7 8 9 10]
[10 11 12 13 14 15 16 17 18 19 20]
[10 11 12 13 14 15]
piojo's answer looks like it would work (though I haven't tried it).
Another approach to turning a method into a variable is to use indirection:
class Foo {
method bar($a) {
$a * 2
}
}
sub twice(&f, $x) {
f f $x
}
my $foo = Foo.new();
say twice {$foo.bar: $^a}, 1

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

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.