Perl 6 的薛定谔的猫 - Junctions

薛定谔欧文应该是喜欢 Perl 6 的, 因为他的著名的薛定谔的猫可以用 Perl 6 的 Junction表达:

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

这里面发生了什么事情? 我会告诉你全部的!

Anyone 游戏?

拿最简单的来说, Junctions 允许你把一堆值当作单个值。例如, 你可以使用 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!

要从一堆值中创建一个 any Junction, 你可以使用 | 中缀操作符、调用 any 函数或者使用 .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) 在数值上等于 @two 中的任意一个值(any)的话。这个语法糖很甜, 但是我们还可以做的更多。

All for One and Any for None

any Junction 唯一一个你能获得的 Junction。你还可以选择 allanyonenone。当在布尔上下文中时, 它们的意思就像下面这样; 构建 Junction 的函数/方法名和 Junction 自身的名字一样并且下面还列出了构建 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 的子例程的参数。那么会发生什么呢? 对于每一个 Junctioned 的值, 那个子例程都会被调用一次, 并且返回值会是一个 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;
     $n²;
 }
 
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

暴露的副作用可能有点太过神奇并且你可能不想在生产代码中看到它, 但是使用一个子例程来修改原来的 Junctioned 化的值是相当能接受的。执行一个数据库查询来获取"实际的"值并且在之后计算那个条件怎么样:

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

我们一直在期盼你, 请坐。

那个游戏变化了当你的子例程正好期望一个 Junction 作为参数的时候。

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

当我们提供了一个 one Junction 时, 只有正好满足给定值中的其中一个条件才会被触发。当我们提供一个 any Junction 时, 满足条件的任何一个给定值都会触发。

但是! 你没有必要非等着世界为你分发 Junctions。你自己制造一个怎么样呢, 还能在测试条件时节省代码:

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 被设计为时自动线程化的(即 auto-threaded)。尽管在写这篇文章的时候它们只会使用仅仅一个线程, 你不应该依赖它们能以任何可预测的顺序被执行。自动线程化会在 2018 年的某个时间被实现, 所以保持关注... 你不必做任何事情, 你的值得自动线程化的复杂 Junctioned 化的操作可能会在几年之内变得更快。

结论

Perl 6 的 Junctions 是值的叠加态, 它允许你测试多个值就像它们是一个值一样。除了提供非常短并且易读的语法, Junctions 还允许你使用子例程变换叠加值或者使用副作用。

你还可以生成显式操作 Junctions 的子例程或者把提供的多个值转换成 Junctions 以简化代码。

最后, Junctions 被设计为能使用所有你计算机所提供的可用能力并且在不久的将来会做成自动线程化。

Junctions 很精彩, 使用它们, 玩的开心!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容

  • 2009 有用的和有意思的循环 让我们来看一个基本的例子. 这是一个最简单清晰的语法的例子.在这并没有使用括号来包...
    焉知非鱼阅读 547评论 0 0
  • 操作符 操作符优先级 在像 1 + 2 * 3 这样的表达式中, 2 * 3 被首先计算, 因为中缀操作符 * ...
    焉知非鱼阅读 1,394评论 0 1
  • 2016-10-20 号更新。 源文件可以在 github 或 perl6.org上找到. General Rak...
    焉知非鱼阅读 977评论 0 0
  • 第一章 概要 Comming soon! 第二章 基础 假设有一场乒乓球比赛,比赛结果以这种格式记录:Player...
    焉知非鱼阅读 339评论 0 0
  • Perl 6 是 Perl 编程语言家族中的一员. 它仍旧在开发中, 几个解释器和编译器在同时进行. 它引入了很多...
    焉知非鱼阅读 811评论 0 2