is Mu
交点是零个或多个值的无序复合值。交点在许多操作中自动线程化,这意味着该操作对每个交点元素(也称为本征态)执行,结果是所有这些运算符的返回值的交点。
交点在布尔上下文中折叠成单个值,因此在条件、否定或通过so
或?
前缀运算符明确强制转换为 Bool 时使用。这种折叠的语义取决于交点类型,该类型可以是all
、any
、one
或none
。
类型 | 构造函数 | 运算符 | 如果...为真 |
---|---|---|---|
all | all | & | 没有值评估为 False |
any | any | | | 至少有一个值评估为 True |
one | one | ^ | 恰好有一个值评估为 True |
none | none | 没有值评估为 True |
如表格所示,为了创建交点,您使用表示Junction
类型的命令后跟任何对象,或者在对象上调用.all
、.none
或.one
。
say so 3 == (1..30).one; # OUTPUT: «True»say so ("a" ^ "b" ^ "c") eq "a"; # OUTPUT: «True»
交点是非常特殊的对象。它们不属于Any
层次结构,只是作为任何其他对象,是Mu
的子类。这为大多数方法启用了一个特性:自动线程化。当交点绑定到不接受类型为Junction
的值的代码对象的某个参数时,就会发生自动线程化。签名绑定会针对交点的每个值重复,而不是产生错误。
示例
my = 1|2;if 3 == + 1
首先自动线程化infix:<+>
运算符,生成交点2|3
。下一个自动线程化步骤是infix:<==>
,它生成False|True
。if
条件在布尔上下文中评估交点,将其折叠为True
。因此,代码打印yes\n
。
Junction
的类型不会影响自动线程化后结果Junction
中的项目数。例如,在Hash
键查找期间使用oneJunction
,仍然会导致具有多个项目的Junction
。只有在布尔上下文中,Junction
的类型才会发挥作用
my = :42foo, :70bar;say :exists; # OUTPUT: «one(True, False)»say so :exists; # OUTPUT: «True»say :exists; # OUTPUT: «one(True, True)»say so :exists; # OUTPUT: «False»
请注意,编译器允许(但不要求)并行化自动线程化(以及一般的交点行为),因此通常错误地将交点自动线程化到具有副作用的代码上。
自动线程化意味着自动线程化的函数还将返回它通常会返回的值的交点。
(1..3).head( 2|3 ).say; # OUTPUT: «any((1 2), (1 2 3))»
由于.head
返回一个列表,因此自动线程化版本返回一个列表的Junction
。
'walking on sunshine'.contains( 'king'&'sun' ).say; # OUTPUT: «all(True, True)»
同样,.contains
返回一个布尔值;因此,自动线程化版本返回一个布尔值的Junction
。一般来说,所有采用类型为T
的参数并返回类型为TT
的方法和例程也将接受T
的交点,返回TT
的交点。
允许实现对 Junction 进行短路。例如,如果条件的结果已经从已执行的例程调用中完全确定(仅一个真返回值足以知道整个 Junction 为真),则以下代码中的一个或多个例程调用(a()
、b()
或 c()
)可能根本不会执行
if a() | b() | c()
Junction 旨在用作布尔上下文的匹配器;不支持对 Junction 进行自省。如果您感到有必要自省 Junction,请改用 Set
或相关类型。
用法示例
my = <1 2 "Great">;.append(True).append(False);my = grep Bool|Int, ;sub is_prime(Int ) returns Boolmy = grep & / 1$ /, 2..100;say ; # OUTPUT: «[11 31 41 61 71]»my = <~ .git>;for dir(".")
在对可能产生空列表的参数使用 all
时应特别小心
my = ();say so all() # True, because there are 0 Falses
要表示“全部,但至少一个”,可以使用 @a && all(@a)
my = ();say so && all(); # OUTPUT: «False»
在自动线程处理方面,否定运算符是特殊情况。$a !op $b
在内部被重写为 !($a op $b)
。外部否定会折叠所有 Junction,因此返回值始终是一个普通的 Bool
。
my = 'yes';my = <no none never>;if !eq any
请注意,如果没有此特殊情况,则对于一侧为非平凡列表的表达式,如 $word ne any @words
,始终会评估为 True
。
为此,infix:<ne>
算作 infix:<eq>
的否定。
通常,使用正比较运算符和否定 Junction 更具可读性
my = 'yes';my = <no none never>;if eq none
故障和异常§
就 Junction 而言,Failure
只是与其他值一样的值
my = +any "not a number", "42", "2.1";my = gather for ->.say; # OUTPUT: «[42 2.1]»
在上面,我们对 Junction
使用了前缀 +
运算符,将其中的字符串强制转换为 Numeric
。由于当不包含数字的 Str
被强制转换为 Numeric
时,该运算符会返回 Failure
,因此 Junction
中的元素之一是 Failure
。只有在使用或下沉之前,Failure
才会变成异常,但我们可以检查已定义性以避免这种情况。这就是我们在循环中对 Junction 的元素进行遍历时所做的,仅在已定义这些元素时才将它们添加到列表中。
如果您尝试将 Failure
用作值,则会引发异常——就像此 Failure
是独立的,不属于 Junction
一样
my = +any "not a number", "42", "2.1";try say == 42;$! and say "Got exception: $!.^name()";# OUTPUT: «Got exception: X::Str::Numeric»
请注意,如果在计算 Junction
中的任何值时引发异常,则会引发异常,就像在独立计算有问题的值且不使用 Junction
一样;您不能只计算有效的值而忽略异常
sub calc ()my = any 1..42;say try calc ; # OUTPUT: «Nil»
上面只有一个值会导致异常,但 try
块 的结果仍然是 Nil
。一种可能的解决方法是作弊,单独评估 Junction
的值,然后根据结果重新创建 Junction
sub calc ()my = any 1..42;= any (gather ».take).grep: ;say so == 42; # OUTPUT: «True»
智能匹配§
请注意,在 ~~
的右侧使用 Junction
的方式与在其他运算符中使用 Junction 的方式略有不同。
考虑此示例
say 25 == (25 | 42); # OUTPUT: «any(True, False)» – Junctionsay 25 ~~ (25 | 42); # OUTPUT: «True» – Bool
原因是 ==
(以及大多数其他运算符)都受自动线程处理的影响,因此您将获得一个交点作为结果。另一方面,~~
将在右侧(在这种情况下是在交点上)调用 .ACCEPTS
,结果将是 Bool
。
方法§
方法 new§
multi method new(Junction: \values, Str :!)multi method new(Junction: Str \type, \values)
这些构造函数从定义它的类型和一组值构建一个新的交点。
my = Junction.new(<Þor Oðinn Loki>, type => "all");my = Junction.new( "one", 1..6 )
两个多值之间的主要区别在于 Junction
的类型如何作为参数传递;要么作为第一个参数按位置传递,要么使用 type
作为命名参数传递。
方法 defined§
multi method defined(Junction:)
检查是否已定义,而不是检查布尔值。
say ( 3 | Str).defined ; # OUTPUT: «True»say (one 3, Str).defined; # OUTPUT: «True»say (none 3, Str).defined; # OUTPUT: «False»
Failure
也被认为是未定义的
my =Failure.new;say (one 3, ).defined; # OUTPUT: «True»
从 6.d 开始,此方法将自动进行线程处理。
方法 Bool§
multi method Bool(Junction:)
折叠 Junction
并根据类型和它所包含的值返回一个布尔值。每个元素都转换为 Bool
。
my = Junction.new( "one", 1..6 );say .Bool; # OUTPUT: «False»
在这种情况下,所有元素都转换为 True
,因此断言其中只有一个元素是错误的。
my = Junction.new( "one", <0 1> );say .Bool; # OUTPUT: «True»
在这种情况下,其中只有一个元素为真,即 1
,因此对 Bool
的强制转换返回 True
。
方法 Str§
multi method Str(Junction:)
自动对 .Str
方法进行线程处理,使其元素返回结果为 Junction
。使用 .Str
方法(print 和 put)的输出方法是自动线程处理交点的特殊情况,尽管它们能够接受 Mu
类型。
方法 iterator§
multi method iterator(Junction:)
返回一个迭代器,该迭代器对转换为 List
的 Junction
进行迭代。
方法 gist§
multi method gist(Junction:)
折叠 Junction
并返回一个 Str
,该字符串由交点的类型及其组件的 要点 组成
<a 42 c>.all.say; # OUTPUT: «all(a, 42, c)»
方法 raku§
multi method raku(Junction:)
折叠 Junction
并返回一个 Str
,该字符串由其组件的 raku 组成,这些组件 求值 为具有等效组件的等效 Junction
<a 42 c>.all.raku.put; # OUTPUT: «all("a", IntStr.new(42, "42"), "c")»
中缀 ~
§
multi infix:<~>(Str , Junction )multi infix:<~>(Junction , Str )multi infix:<~>(Junction \a, Junction \b)
中缀 ~
连接可用于将交点合并为一个交点或将交点与字符串合并。结果交点将合并所有元素,就好像它们被连接到一个嵌套循环中一样
my = 1|3|5;my = 2|4|6;my = ~ ;say ; # OUTPUT: «any(12, 14, 16, 32, 34, 36, 52, 54, 56)»say "Found 34!" if 34 == ; # OUTPUT: «Found 34!»my = "0" ~ ;say "Found 03" if "03" == ; # OUTPUT: «Found 03!»my = ~ "1";say "Found 11" if 11 == ; # OUTPUT: «Found 11!»
另一方面,将字符串用作一个参数的 ~
版本只会将字符串与 Junction 的每个成员连接起来,从而创建一个具有相同数量元素的另一个 Junction。
另请参阅§
http://perl6maven.com/perl6-is-a-value-in-a-given-list-of-values
https://perl6advent.wordpress.com/2009/12/13/day-13-junctions/