薛定諤歐文應(yīng)該是喜歡 Perl 6 的, 因為他的著名的薛定諤的貓可以用 Perl 6 的 Junction表達(dá):
my $cat = 'dead' | 'alive';
say "cat is both dead and alive" if $cat eq 'dead' and $cat eq 'alive';
# OUTPUT:
# cat is both dead and alive
這里面發(fā)生了什么事情? 我會告訴你全部的!
Anyone 游戲?
拿最簡單的來說, Junctions 允許你把一堆值當(dāng)作單個值闪水。例如, 你可以使用 any
Junction 來測試一個變量是否等于所給定值中的任意一個:
say 'it matches!' if 'foo' eq 'foo' | 'bar' | 'ber';
say 'single-digit prime' if 5 == any ^9.grep: *.is-prime;
my @values = ^100;
say "it's in there!" if 42 == @values.any;
# OUTPUT:
# it matches!
# single-digit prime
# it's in there!
要從一堆值中創(chuàng)建一個 any
Junction, 你可以使用 |
中綴操作符、調(diào)用 any
函數(shù)或者使用 .any
方法偿警。上面的條件會返回 True 如果 Junction 中的任意一個(any
) 值匹配所給定的值的話晾匠。事實上, 沒有人能阻止你在兩端都使用 Junction:
my @one = 1..10;
my @two = 5..15;
say "There's overlap!" if @one.any == @two.any;
# OUTPUT:
# there's overlap!
運算符會返回 True 如果 @one
中的任意一個值(any
) 在數(shù)值上等于 @two
中的任意一個值(any
)的話匣吊。這個語法糖很甜, 但是我們還可以做的更多。
All for One and Any for None
any
Junction 唯一一個你能獲得的 Junction奏瞬。你還可以選擇 all
衷模、any
指黎、one
和 none
朋凉。當(dāng)在布爾上下文中時, 它們的意思就像下面這樣; 構(gòu)建 Junction 的函數(shù)/方法名和 Junction 自身的名字一樣并且下面還列出了構(gòu)建 Junction 的中綴操作符:
-
all
— 所有的值都被計算為 True(使用中綴&
) -
any
— 至少其中的一個值被計算為 True(使用中綴|
) -
one
— 正好其中有一個值被計算為 True(使用中綴^
) -
none
— 沒有一個值被計算為 True(沒有可用的中綴)
使用 all
JUnction 時要特別注意:
my @values = 2, 3, 5;
say 'all primes' if @values.all ~~ *.is-prime;
my @moar-values;
say 'also all primes' if @moar-values.all ~~ *.is-prime;
即使它沒有值的時候也會返回 True, 這可能不是你想要的。在那些情況下, 你可以使用:
my @moar-values;
say 'also all primes' if @moar-values and @moar-values.all ~~ *.is-prime;
Call Me, Baby
你可以把 Junctions 用作并不期望 Junction 的子例程的參數(shù)醋安。那么會發(fā)生什么呢? 對于每一個 Junctioned 的值, 那個子例程都會被調(diào)用一次, 并且返回值會是一個 Junction:
sub caculate-things($n) {
say "$n is prime" if $n.is-prime;
say "$n is an even number" if $n %% 2;
say "$n is pretty big" if $n > 1e6;
$n2;
}
my @values = 1, 5, 42, 1e10.Int;
say 'EXACTLY ONE square is larger than 1e10'
if 1e10 < calculate-things @values.one;
# OUTPUT:
# 5 is a prime
# 42 is an even number
# 10000000000 is an even number
# 10000000000 is pretty big
# EXACTLY ONE square is larger than 1e10
暴露的副作用可能有點太過神奇并且你可能不想在生產(chǎn)代碼中看到它, 但是使用一個子例程來修改原來的 Junctioned 化的值是相當(dāng)能接受的杂彭。執(zhí)行一個數(shù)據(jù)庫查詢來獲取"實際的"值并且在之后計算那個條件怎么樣:
use v6;
use DBIish;
my $dbh = DBIish.connect: 'SQLite', :database<test.db>;
sub lookup ($id) {
given $dbh.prepare: 'SELECT id, text FROM stuff WHERE id = ?' {
.execute: $id;
.allrows[0][1] // '';
}
}
my @ids = 3, 5, 10;
say 'yeah, it got it, bruh' if 'meow' eq lookup @ids.any;
# OUTPUT (the database has a row with id = 5 and text = 'meow'):
# yeah, it got it, bruh
我們一直在期盼你, 請坐。
那個游戲變化了當(dāng)你的子例程正好期望一個 Junction 作為參數(shù)的時候吓揪。
sub do-stuff (Junction $n) {
say 'value is even' if $n %% 2;
say 'value is prime' if $n.is-prime;
say 'value is large' if $n > 1e10;
}
do-stuff (2, 3, 1e11.Int).one;
say '---';
do-stuff (2, 3, 1e11.Int).any;
# OUTPUT:
# value is large
# ---
# value is even
# value is prime
# value is large
當(dāng)我們提供了一個 one
Junction 時, 只有正好滿足給定值中的其中一個條件才會被觸發(fā)亲怠。當(dāng)我們提供一個 any
Junction 時, 滿足條件的任何一個給定值都會觸發(fā)。
但是! 你沒有必要非等著世界為你分發(fā) Junctions柠辞。你自己制造一個怎么樣呢, 還能在測試條件時節(jié)省代碼:
sub do-stuff (*@v) {
my $n = @v.one;
say "$n is even" if $n %% 2;
say "$n is prime" if $n.is-prime;
say "$n is large" if $n > 1e10;
}
do-stuff 2, 3, 1e11.Int;
say '---';
do-stuff 42;
# OUTPUT:
# one(2, 3, 100000000000) is large
# ---
# one(42) is even
沒有人想過將來嗎?
還有一個小秘密: Junctions 被設(shè)計為時自動線程化的(即 auto-threaded)团秽。盡管在寫這篇文章的時候它們只會使用僅僅一個線程, 你不應(yīng)該依賴它們能以任何可預(yù)測的順序被執(zhí)行。自動線程化會在 2018 年的某個時間被實現(xiàn), 所以保持關(guān)注... 你不必做任何事情, 你的值得自動線程化的復(fù)雜 Junctioned 化的操作可能會在幾年之內(nèi)變得更快叭首。
結(jié)論
Perl 6 的 Junctions 是值的疊加態(tài), 它允許你測試多個值就像它們是一個值一樣习勤。除了提供非常短并且易讀的語法, Junctions 還允許你使用子例程變換疊加值或者使用副作用。
你還可以生成顯式操作 Junctions 的子例程或者把提供的多個值轉(zhuǎn)換成 Junctions 以簡化代碼焙格。
最后, Junctions 被設(shè)計為能使用所有你計算機(jī)所提供的可用能力并且在不久的將來會做成自動線程化图毕。
Junctions 很精彩, 使用它們, 玩的開心!