Why no "each" method on Perl6 sequences? - raku

Sometimes I'll start writing a chain of method calls at the Perl 6 REPL, like:
".".IO.dir.grep(...).map(...).
...and then I realize that what I want to do with the final list is print every element on its own line. I would expect sequences to have something like an each method so I could end the chain with .each(*.say), but there's no method like that that I can find. Instead I have to return to the beginning of the line and prepend .say for. It feels like it breaks up the flow of my thoughts.
It's a minor annoyance, but it strikes me as such a glaring omission that I wonder if I'm missing some easy alternative. The only ones I can think of are ».say and .join("\n").say, but the former can operate on the elements out of order (if I understand correctly) and the latter constructs a single string which could be problematically large, depending on the input list.

You can roll your own.
use MONKEY;
augment class Any
{
method each( &block )
{
for self -> $value {
&block( $value );
}
}
};
List.^compose;
Seq.^compose;
(1, 2).each({ .say });
(2, 3).map(* + 1).each({ .say });
# 1
# 2
# 3
# 4
If you like this, there's your First CPAN module opportunity right there.

As you wrote in the comment, just an other .map(*.say) does also create a line with True values when using REPL. You can try to call .sink method after the last map statement.
".".IO.dir.grep({$_.contains('e')}).map(*.uc).map(*.say).sink

Related

Cannot assign an if statement to a variable

The problem here is that I do not understand well the difference between statements and blocks in control flow.
Looking the ternary operator I can use it to assign a variable. But this is an operator, so it is like applying a function--isn't it?
> my $variable = True ?? 34 !! 42;
34
since in the raku documentation says:
if documentation
if
To conditionally run a block of code, use an if followed by a
condition. The condition, an expression, will be evaluated immediately
after the statement before the if finishes. The block attached to the
condition will only be evaluated if the condition means True when
coerced to Bool. Unlike some languages the condition does not have to
be parenthesized, instead the { and } around the block are mandatory:
do documentation
do
The simplest way to run a block where it cannot be a stand-alone statement is by writing do before it:
so this should work in both cases:
> my $variable = do {34};
34
> my $variable = if True {34;} else {43;}
===SORRY!===
Word 'if' interpreted as a listop; please use 'do if' to introduce the statement control word
------> my $variable = if⏏ True {34;} else {43;}
Unexpected block in infix position (two terms in a row)
------> my $variable = if True⏏ {34;} else {43;}
as said in the error I need to add the do:
> my $variable = do if True {34;} else {43;}
34
So the if really does not run the block...or what is the real problem here?
TL;DR: The actual difference is between statement and expression, not statement and block. do is a statement prefix that creates expressions.
if actually creates a statement (anything that is run in Raku is), however, what it's not is an expression. do is a statement prefix, and what it does is turn statements into expressions.
However, if is not really a first-class function that you can assign to a variable or handle around. Whenever you find pieces of syntax such as that one (or for, for instance), you need to prefix them with do to "expressionify" them.
say &say.^name;# OUTPUT: «Sub␤» say &do.^name; # OUTPUT: «===SORRY!=== Error while compiling <tmp>␤Undeclared routine:␤...
say &if.^name; # OUTPUT: «===SORRY!=== Error while compiling <tmp>␤Undeclared routine:␤ if used at line 1␤␤»
So if, by itself, does not create a block, it does not create an expression, it simply creates a statement. You need to precede it with do if you want it to actually turn it into a expression. It does run the block that's behind it, however.
Let's go back to the original question, statements and blocks. Blocks are objects, first-class citizens. You can use them, apply them, pass them around.
my &ifs = { if $_ {34} else {43}};
ifs(True).say; # OUTPUT: «34␤»
Statements are throwaway blocks you simply run. In some cases, they are also expressions: they yield a result which, then, you can assign.
my &ifs = { if $_ {34} else {43}};
my $result = ifs(True).say; # OUTPUT: «34␤»
say $result; # OUTPUT: «True␤»
The ifs(True).say statement prints to output, it also produces a result that can be assigned. All three lines are also statements, and as a matter of fact, expressions too.
Some control structures, however, do not create expressions.
Some others do; for creates a expression; while does not.
if is an example of this. They don't produce a result. You use them for the side effects: running a statement (if true) or another (if not). You might turn them into a block, as above, and pass them around. Or you can just precede them with do and make them produce a throwaway result, which you can then use.
So it will very much depend on your actual use case. You can surround the if statement with curly braces and create a block; or you can simply use the result creating an expression. Or you might want to use it just for the side effects, doing nothing.

Put named capture from regex in Subset into a variable in the signature

Consider
subset MySubset of Str where * ~~ /^ \d $<interesting> = ( \d+ ) $/;
Now I want to use the subset as a Type in my signature, but put the captured part(s) into a variable via unpacking, kinda like
sub f( MySubset $( :$interesting ) )
{
say $interesting;
}
f( "12345678" ); # should say 2345678
That's not working of course. Is it even possible to do this?
Subsignature unpacking is about turning a value into a Capture and matching against that.
class Point {
has ( $.x, $.y );
}
my ( :$x, :$y ) := Point.new( x => 3, y => 4 ).Capture;
say "[$x,$y]"; # [3,4]
Since a Str doesn't have a public attribute named $.interesting, it won't match.
A subset is just extra code to check a value more completely than you could otherwise do. It does not turn the value into a new type.
It would be more likely to work if you used $<interesting>.
sub f( MySubset )
{
say $<interesting>;
}
Of course since blocks get their own $/, this also does not work.
While it might be nice to pass information from a subset to a signature, I am not aware of anyway to do it.
As a side note, where already does smart matching so it is an incredibly bad idea to use ~~ inside of it.
This is basically how your subset works:
"12345678" ~~ ( * ~~ /…/ )
In this particular case you could just use .substr
sub f( MySubset $_ ) {
.substr(1)
}
I can't figure out a way with a subset type, however there is a way - with a little...creativity - to do a match and unpack it in the signature.
Match inherits from Capture, so having one be unpacked in a signature is straightforward - if only we can arrange for there to be a parameter that contains the Match we wish to unpack. One way to do that is to introduce a further parameter with a default. We can't really stop anyone passing to it - though we can make it a pain to do so by using the anonymous named parameter. Thus, if we write this:
sub foo($value, :$ (:$col, :$row) = $value.match(/^$<col>=[<:L>+]$<row>=[\d+]$/)) {
say $col;
say $row;
}
And call it as foo("AB23"), the output is:
「AB」
「23」
Finally, we may factor the rule out to a named token, achieving:
‌‌my token colrow { ^$<col>=[<:L>+]$<row>=[\d+]$ }
sub foo($value, :$ (:$col, :$row) = $value.match(&colrow)) {
say $col;
say $row;
}
I'm pretty sure wheres (and subsets) just answer True/False. Brad concurs.
There are essentially always metaprogramming answers to questions but I presume you don't mean that (and almost never dig that deep anyway).
So here are a couple ways to get something approaching what you seem to be after.
A (dubious due to MONKEYing) solution based on Brad's insights:
use MONKEY;
augment class Str {
method MyMatch { self ~~ / ^ \d $<interesting> = ( \d+ ) $ / }
}
class MyMatch is Match {}
sub f( MyMatch() $foo (:$interesting) ) { say ~$interesting }
f( "12345678" ); # 2345678
The bad news is that the sub dispatch works even if the string doesn't match. The doc makes it clear that the coercer method (method MyMatch in the above) cannot currently signal failure:
The method is assumed to return the correct type — no additional checks on the result are currently performed.
One can hope that one day augmenting a class will be an officially respectable thing to do (rather than requiring a use MONKEY...) and that coercing can signal failure. At that point I think this might be a decent solution.
A variant on the above that binds to $/ so you can use $<interesting>:
use MONKEY;
augment class Str {
method MyMatch { self ~~ / ^ \d $<interesting> = ( \d+ ) $ / }
}
class MyMatch is Match {}
sub f( MyMatch() $/ ) { say ~$<interesting> }
f( "12345678" ); # 2345678
Another way that avoids MONKEYing around is to use a subset as you suggest but separate the regex and subset:
my regex Regex { ^ \d $<interesting> = ( \d+ ) $ }
subset Subset of Str where &Regex;
sub f( Subset $foo ; $interesting = ~($foo ~~ &Regex)<interesting> )
{
say $interesting;
}
f( "12345678" ); # 2345678
Notes:
The regex parses the input value at least twice. First in the Subset to decide whether the call dispatches to the sub. But the result of the match is thrown away -- the value arrives as a string. Then the regex matches again so the match can be deconstructed. With current Rakudo, if the sub were a multi, it would be even worse -- the regex would be used three times because Rakudo currently does both a trial bind as part of deciding which multi to match, and then does another bind for the actual call.
Parameters can be set to values based on previous parameters. I've done that with $interesting. A signature can have parameters that are part of dispatch decisions, and others that are not. These are separated by a semi-colon. I've combined these two features to create another variable, thinking you might think that a positive thing. Your comment suggest you don't, which is more than reasonable. :)

Print 0001 to 1000 in Kotlin. How to add padding to numbers?

I want to print 0001 (note the 3 preceding 0s), and incremental 1 at a time, and reach 1000 to stop. How could I do that in Kotlin without complex appending the 0s myself?
The below is not helping as it will not have preceding 0s.
for (i in 1..1000) print(i)
You can use padStart:
(0..1000)
.map { it.toString().padStart(4, '0') }
.forEach(::println)
It’s part of the Kotlin Standard Library and available for all platforms.
If you are satisfied with a JVM-specific approach, you can do what you'd to in Java:
(1..1000).forEach { println("%04d".format(it)) }
String.format is an extension function defined in StringsJVM and it delegates straight to the underlying String.format, so it's not in the universal standard library.
In Kotlin you can use String.format() (the same as in Java):
"%04d".format(i)
In your case, you can write down it in the following way:
(1..1000).forEach { println("%04d".format(it)) }
With PadStart and without any map or multiple loops,
(0..1000).forEach { println(it.toString().padStart(4, '0')) }
Just to be clear, for-loops are fine too:
for(i in 1..1000)
println("%04d".format(i))
Using a string template will call toString() under the hood and make the call even shorter:
(0..1000).forEach { println("$it".padStart(4, '0')) }
Mapping it first, is unecessary effort.

How to require 1 or more of an argument in MAIN

Right now, I have a MAIN sub that can take one or more string arguments. But I am using two separate parameters for MAIN to do it:
sub MAIN (
Str:D $file,
*#files,
) {
#files.prepend: $file;
# Rest of the program
}
Now I am wondering if there's a more idiomatic way to achieve this, as my current solution feels a little clunky, and not very Perly.
You could do it with a proto sub
proto sub MAIN ( $, *# ){*}
multi sub MAIN ( *#files ) {
# Rest of the program
}
or with sub-signature deparsing
sub MAIN ( *#files ($,*#) ) {
# Rest of the program
}
At the risk of "over answering" - my take on "Perly" is concise as possible without becoming obscure (perhaps I'm just replacing one subjective term with two others... :-)
If you have a "slurpy" array as the only parameter, then it will happily accept no arguments which is outside the spec you put in the comments. However, a positional parameter is compulsory by default and proto's are only necessary if you want to factor out constraints on all multi's - presumably overkill for what you want here. So, this is enough:
sub MAIN($file , *#others) {
say "Received file, $file, and #others.elems() others."
}
This is close to what mr_ron put - but why not go with the default Usage message that MAIN kindly whips up for you by examining your parameters:
$ ./f.pl
Usage:
./f.pl <file> [<others> ...]
Some might say I cheated by dropping the Str type constraint on the first parameter but it really doesn't buy you much when you're restricting to strings because numerics specified at the CLI come through as type IntStr (a kind-of hybrid type) that satisfies a Str constraint. OTOH, when constraining CLI parameters to Num or Int, Perl6 will check that you're actually putting digits there - or at least, what unicode considers digits.
If you're wanting actual filenames, you can save yourself a validation step by constraining to type IO(). Then it will only work if you name a file. And finally, putting where .r after the parameter will insist that it be readable to boot:
sub MAIN(IO() $file where .r, *#others) { ...
One short line that insists on one compulsory argument that is a filename referencing a readable file, with a varying number of other parameters and a useful Usage message auto generated if it all goes sideways...
Perhaps good enough answer here:
sub MAIN(*#a where {.elems > 0 and .all ~~ Str}) {
say "got at least 1 file name"
}
sub USAGE {
say "{$*PROGRAM-NAME}: <file-name> [ <file-name> ... ]"
}
Based on docs here:
https://docs.perl6.org/type/Signature#Constraining_Slurpy_Arguments
You can also try and use simply dynamic variables:
die "Usage: $*EXECUTABLE <file> <file2>*" if !+#*ARGS;
my #files = #*ARGS;
where #*ARGS is an array with the arguments issued into the command line
You can even use #*ARGFILES, since they are actually files

How to loop through all params in Less mixin

I'm writing a Less mixin.
I want to be able to pass the mixin several parameters. The first will be a string. The rest, an infinite number of parameters, will be value pairs.
In my mixin how can I loop through the infinite number of parameters?
For example one time I will call...
.my-mixin(#name, #foo: bar, #hello: world);
and another time...
.my-mixin(#name, #iam: cool, #youare: lame, #someoneis: awesome);
Here's what it would look like if Less supported JS/PHP...
.my-mixin() {
#name: #arguments[0]; //First param
for (#arguments as #label => #value) {
#label: #value;
}
}
Is this possible?
In fact you ask two questions. First how to create a mixin that can accept an endless number of parameters, and secondly who to iterate over the list / array of parameters.
Less has the special ... syntax to create mixins with an endless number of parameters. The official documentation can be found here: Advanced arguments and the #rest variable. An example / use case can be found at Can I define a LESS mixin to generate a transition-property with a variable number of parameters?.
The special ... syntax can be used to assign the parameter list to a variable by adding the variable name before the ...:
.mixin(#parameter1, #endlesslistofparameters...) {}
The #endlesslistofparameters variable now contains a list of parameters, you can use the Less list functions to extract a value from this list (or find its length):
length() returns the length of a list and extract(#list,position) return the value of a certain position in the list. Notice that the first value is on position 1 and not 0.
Finally you can use a loop to iterate over this list of arguments.
In Less a mixin can call itself. Such recursive mixins, when combined
with Guard Expressions and Pattern Matching, can be used to create
various iterative/loop structures.
See also: Loop over an array of name value pairs in LESS
All together i think you can write something like that shown below:
.my-mixin(#name,#properties...) {
.setproperties(#iterator:1) when (#iterator <= length(#properties)) {
#propertyname: extract(extract(#properties,#iterator),1);
#{propertyname}: extract(extract(#properties,#iterator),2);
.setproperties((#iterator + 1));
}
.#{name} {
.setproperties();
}
}
.my-mixin(jared; iam cool, youare lame, someoneis awesome);
The preceding Less code will compile into the following CSS code:
.jared {
iam: cool;
youare: lame;
someoneis: awesome;
}
And than also notice that Less allows you to Passing Rulesets to Mixins since version 1.7, which enables you to write:
.my-mixin2(#name,#properties) {
.#{name} {
#properties();
}
}
.my-mixin2(jared; {iam: cool; youare: lame; someoneis: awesome;});