11

I can write something like this (elem here is an XML::Element but it doesn't really matter):

for $elem.nodes { when XML::Element { ... } when XML::Text { ... } ... default { note qq{Ignoring unknown XML node "$_".} } } 

which looks nice, but doesn't give me a readable name for $_ inside the code using it, which is why I'd prefer to write this:

for $elem.nodes -> $child { when XML::Element { ... } when XML::Text { ... } ... default { note qq{Ignoring unknown XML node "$child".} } } 

but this doesn't work because now $_ isn't set, and so I actually need to write

for $elem.nodes -> $child { given $child { when XML::Element { ... } when XML::Text { ... } ... default { note qq{Ignoring unknown XML node "$child".} } } } 

which is a bit redundant and adds an extra level of indentation.

It's definitely not the end of the world, but am I missing some simple way to have both a readable variable name and avoid given?

2
  • 1
    I dream of a "forgiven"... who knows maybe some day... Commented Jan 25, 2023 at 21:34
  • Is smartmatching elegant enough? :-) Commented Feb 28, 2024 at 19:46

4 Answers 4

9

You can bind the variable above the when statements, it's a little uglier but it does the job.

for $elem.nodes { my $child = $_; when XML::Element { say 'I am XML!' } when XML::Text { say 'I am text!' } default { say "I am default: $child" } } 

Edit: In Raku I think it is perfectly reasonable to stick to using $_ seeing as the idea of $_ has been around for quite some time.

Sign up to request clarification or add additional context in comments.

3 Comments

should this be $child := $_;?
@p6steve it can be, it shouldn't make a difference in this case though.
Thanks, I guess this is indeed the most reasonable answer, I just hoped there might be some magic way to bind both $child and $_ to the loop value at the same time, somehow -- but if there is none, this is the most clear and concise way to do what I want.
8
for @a -> $x { { when 2 { say "$x ... a" } when 4 { say "$x ... b" } } given $x } 

naughty double curlies and a post-given?

2 Comments

my only defence of this shameless use of double curlies is JavaScript thing(function() { ... }); style code
Thanks for the idea, it's nice to know that it works, but I wouldn't want to defend writing this in a code review...
1

Smartmatching the when condition(s):

my @a = <cat rabbit 2 dog>; say @a; say "____\n"; for @a -> $x { when $x ~~ 2 { say "$x ... a" }; when $x ~~ 4 { say "$x ... b" }; #default { say $_ if $x.defined; }; #uncomment to catch fall-through; } ; 

Returns:

[cat rabbit 2 dog] ____ 2 ... a 

Note: default above returns (Any) for any fall-through, which tells us that $_ is unset. You can change default to something more useful like:

default { say "$x is default" if $x.defined };



Longer Example:

% cat ~/exemel_text.xml <?xml version="1.0"?> <root> <file>text1</file> <file>text2</file> <file>text3</file> <file>text4</file> </root> % raku -MXML -e 'my $mydocument=open-xml($*ARGFILES.Str); my @array = $mydocument.root.nodes[1,3,5,7...*]; #odd elements only for @array -> $scalar { when $scalar ~~ XML::Element {say "$scalar is an XML::Element!"}; when $scalar ~~ XML::Node {say "$scalar is an XML::Node!"}; default { say $_ if $scalar.defined }; };' ~/exemel_text.xml <file>text1</file> is an XML::Element! <file>text2</file> is an XML::Element! <file>text3</file> is an XML::Element! <file>text4</file> is an XML::Element! 

https://github.com/raku-community-modules/XML

4 Comments

This is also nice, thanks, although I'm not sure if it's better to repeat $var ~~ in every line or just do $var = $_ once, as in the other answer.
Thx! I think given serves to topicalize each when statement, which you can circumvent by an explicit smartmatch. So you can do a for/when loop without too much inconvenience.
FYI, if you have any further interest in manipulating XML in Raku, please peruse this repo (any comments/suggestions appreciated!): github.com/raku-community-modules/XML
Thanks, I'll keep this in mind when I have to do something with XML the next time (hopefully not too soon :-)
1

With a third-party library:

use Slang::Forgiven; forgiven $elem.nodes -> $child { when XML::Element { ... } when XML::Text { ... } ... default { note qq{Ignoring unknown XML node "$child".} } } 

It introduces a keyword called "forgiven" to the grammar such that it is like the good-old for loops but also topicalizes the parameter(s) of the following block, i.e., makes $_ an alias to them, allowing, e.g., both $child and $_ to be used for the same thing.

Disclaimer: author here.

1 Comment

Interesting idea, thanks for letting me know!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.