How to find out if a given value is among some values? Similar to the IN operator in SQL or what you might expect from sets.
In Perl 6 there is the any() function that provides some functionality similar to the IN word in SQL. Let's see how it works:
use v6; my @weekdays = <Monday Tuesday Wednesday Thursday Friday Saturday Sunday>; my $day = "Tuesday"; say $day eq any(@weekdays) ?? "$day is a weekday" !! "$day is NOT a weekday";
The above code will print
Tuesday is a weekday
What happens here is that perl will try to compare each element in the @weekdays array with the content of the $day scalar using eq. If any of them results in true then the expression is true.
Side note: The ?? !! pair is the ternary operator of Perl 6. Its syntax is
CONDITION ?? VALUE_IF_TRUE !! VALUE_IF_FALSE;
In other languages (including Perl 5) it is usually written as ? : but apparently it is not used that often so in order to please David A. Huffman and to give way for other, more frequently used operations, this operator became longer in Perl 6.
For the completeness let's see what happens when none of the values match:
use v6; my @weekdays = <Monday Tuesday Wednesday Thursday Friday Saturday Sunday>; my $other = "Holiday"; say $other eq any(@weekdays) ?? "$other is a weekday" !! "$other is NOT a weekday";
The same code but without a matching value will print:
Holiday is NOT a weekday
In the next example we'll see that the any function can be used with other comparison operators such as the numerical less than operator:
use v6; my @numbers = (6, -12, 20); say any(@numbers) < 0 ?? "There is a negative number" !! "No negative number here";
The result is:
There is a negative number
You can use other operators as well.
It works in case there is no negative number too:
use v6; my @positive_numbers = (6, 12, 20); say any(@positive_numbers) < 0 ?? "There is a negative number" !! "No negative number here";
Output:
No negative number here
There are other functions too, not only the *any* function: (all, one and none)
use v6; my @positive_numbers = (6, 12, 20); say none(@positive_numbers) < 0 ?? "No negative number here" !! "There is a negative number";
Will print:
No negative number here
use v6; my @positive_numbers = (6, 12, 20); say all(@positive_numbers) > 0 ?? "All are positive numbers" !! "There is a NOT positive number";
Will print:
All are positive numbers
Use whichever fits the best the sentence you are writing.
Sometimes you have a value and need to check if it equals to any of the listed values:
use v6; my $n = 12; say ($n == 23 or $n == 42) ?? "ok" !! "not ok"; # not ok
With the any function you can also write like this:
use v6; my $n = 12; say $n == any(23, 42) ?? "ok" !! "not ok"; # not ok
The any function also has an infix operator version which is the single pipe, so you can also write this:
use v6; my $n = 12; say $n == 23|42 ?? "ok" !! "not ok"; # not ok
What all these keywords and the relevant operators do is actually creating a data type that is called a Junction. It is a scalar value that holds multiple values in an unordered way. Similar to a set.
The first example could be written like this:
use v6; my $weekdays = any <Monday Tuesday Wednesday Thursday Friday Saturday Sunday>; my $day = "Tuesday"; say $day eq $weekdays ?? "$day is a weekday" !! "$day is NOT a weekday";
Here we created a junction instead of an array, and then used this junction in the comparison.
In addition to the comparison operations we saw earlier, we can do other operations on junctions. The operation will be executed on each one of the values in the junction and the result will be a new junction with the changed values:
use v6; my $numbers = any(23, 42); $numbers.perl.say; $numbers++; $numbers.perl.say;
This will print the perl representation of the junction:
any(23, 42) any(24, 43)
You can even pass junctions as parameters to functions. The function will be executed on each value separately in an undefined order, and the result will be another junction. For example if we would like to create the 3 character version of the months we can use the following code:
use v6; my $months = any <January February March April May June July August September October November December>; my $short_names = substr($months, 0, 3); $short_names.perl.say;
Which should print
any("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
The weekday example is based on the blog entry of Moritz Lenz I recommend looking at his Perl 6 and Perl 5 to Perl 6 blogs.
That's it for now.
Published on 2012-07-31