According to Raku documentation, routine first
returns Nil
when no values match. However, why doesn't the line say ($result === Nil) ;
(below) print True
?
sub MAIN()
{
my @myNumberList is Array[Int] = [2, 2, 5, 7] ;
my $result = @myNumberList.first( {$_ > 10} ) ;
say '$result' ;
say $result ;
say $result.WHAT ;
say ($result === Nil) ;
} # end sub MAIN
Program output is …
$result
(Any)
(Any)
False
Update
My goal was to determine whether a list or an array contains one or more elements satisfying a given predicate. In the following sample program, the elems
routine returns a value that is greater than 0 if and only if the given list or array contains at least one element satisfying the predicate given in the corresponding call to grep
.
sub MAIN()
{
my $myList = (2, 2, 5, 7) ;
say '$myList' ;
say $myList ;
say $myList.WHAT ;
my $grepResult1 = $myList.grep( * > 10, :p ) ;
say '$grepResult1' ;
say $grepResult1 ;
say $grepResult1.WHAT ;
say ($grepResult1.elems <= 0) ;
my $grepResult2 = $myList.grep( * > 4, :p ) ;
say '$grepResult2' ;
say $grepResult2 ;
say $grepResult2.WHAT ;
say ($grepResult2.elems <= 0) ;
my @myArray = [2, 2, 5, 7] ;
say '@myArray' ;
say @myArray ;
say @myArray.WHAT ;
my $grepResult3 = @myArray.grep( * > 10, :p ) ;
say '$grepResult3' ;
say $grepResult3 ;
say $grepResult3.WHAT ;
say ($grepResult3.elems <= 0) ;
} # end sub MAIN
Program output is …
$myList
(2 2 5 7)
(List)
$grepResult1
()
(Seq)
True
$grepResult2
(2 => 5 3 => 7)
(Seq)
False
@myArray
[2 2 5 7]
(Array)
$grepResult3
()
(Seq)
True
CodePudding user response:
Interesting question that appears to be (somewhat) addressed on the "Traps To Avoid" documentation page. See the specific subheading: "Assignment of Nil can produce a different value, usually 'Any' ". Also, the Raku documentation page on class Nil .
The short answer--as near as I can surmise--is to use smartmatching with a Junction on the right-hand-side:
Sample Code:
sub MAIN()
{
my @myNumberList is Array[Int] = [2, 2, 5, 7] ;
my $result = @myNumberList.first( {$_ > 10} ) ;
say '$result' ;
say $result ;
say $result.WHAT ;
"\n".say;
say Nil ~~ all($result); #True
say Nil ~~ any($result); #True
say Nil ~~ one($result); #True
say Nil ~~ none($result); #False
"\n".say;
my $result2 = @myNumberList.first( {$_ < 10} ) ;
say Nil ~~ all($result2); #False
say Nil ~~ any($result2); #False
say Nil ~~ one($result2); #False
say Nil ~~ none($result2); #True
} # end sub MAIN
Returns:
$result
(Any)
(Any)
True
True
True
False
False
False
False
True
Alternatively, you can simplify the above code (and clean up your output) using .defined
:
for
result
above (where there are no matching values)say $result if $result.defined;
returns nothing;for
result2
above (where the first matching value is 2)say $result2 if $result2.defined;
returns2
.
For further reading to understand how the smartmatch solution(s) posted above came about, look at the following Github issue: "In general, the left side of ~~ should not be auto-threading".
[Also, (at the risk of confusing the reader), take a look at the Raku code posted on the following Perl5 doc page: https://perldoc.perl.org/perlsyn#Differences-from-Raku ].
ADDENDUM: For a discussion on the 'do-something-only-if-defined' idiom in Raku, see Damian Conway's talk "On The Shoulders of Giants", which includes his code for a user-defined ?=
("assign-if-defined") operator.