(+/%#)0:`(>:@$:)@.(3 :'?2')"0 i.10000
Run Code Online (Sandbox Code Playgroud)
像我想的那样工作.答案倾向于1.现在我想以形式表达这个结果
f =: (+/%#)0:`(>:@$:)@.(3 :'?2')"0 i.
f 10000
Run Code Online (Sandbox Code Playgroud)
不行.
通过J中的并置将几个动词串在一起不会创建一个管道,它会创建一个" 动词序列 ",它具有不同的语义.
也就是说,名词短语:
foo bar bar buz 10000
Run Code Online (Sandbox Code Playgroud)
与动词短语不同:
f =: foo bar baz buz
f 10000
Run Code Online (Sandbox Code Playgroud)
如果你想要一个动词管道,你必须使用某种形式的显式组合(即表示,而不是暗示).
最常见的是,管道由一元动词组成(将一个输入转换为一个输出,它成为下一个动词的输入),因此我们使用@:(或者@,但使用它需要更多注意细节),所以语言相当于原名词短语将是:
f =: foo @: bar @: baz @: buz
f 10000
Run Code Online (Sandbox Code Playgroud)
鉴于此,在您的情况下,我们可能会天真地写下:
(+/%#) @: (0:`(>:@$:)@.(3 :'?2')"0) @: i.
Run Code Online (Sandbox Code Playgroud)
注意将中间的动词(0:`(>:@$:)@.(3 :'?2')"0)包装在括号中,因为我们想要在动词零("0)处应用该动词,并且只应用该动词,特别是将mean(+/ % #)应用于整个结果,而不是应用于每个单独的结果.
但是如果我们这样做并运行它,我们很快就会遇到一个问题:无限递归.
在原始名词短语中,动词0:`(>:@$:)@.(3 :'?2')"0独立,因此该动词中的$:(匿名递归)0:`(>:@$:)@.(3 :'?2')"0仅提及0:`(>:@$:)@.(3 :'?2')"0.
然而,一旦我们将三个动词的序列重新组合成一个管道(f上面),然后$:嵌入其中f并因此引用f.
意思是,在这个公式中f,当$:递归1时,首先i.应用于1,得到,0,然后?生成一个随机位,有50%的几率成为1,然后$:递归,这i.适用于....
这是J中的一个很好的陷阱.有两种传统的解决方案.
您可以将代码分解为较小的命名部分:
f =: mean @: converge @: i.
mean =: +/ % #
converge =: 0:`(>:@$:)@.(3 :'?2')"0
Run Code Online (Sandbox Code Playgroud)
因为它隔离了它$:,确保它仅指converge.
同样,您可以在$:内部嵌入一个匿名的显式上下文,主要限制其权限:
f =: (+/%#) @: (verb def '0:`(>:@$:)@.(3 :'?2')"0 y') @: i.
Run Code Online (Sandbox Code Playgroud)
这就像戴上眼罩一样$::现在它看不到了verb def.一些隐性较真可以不惜这种方法,但是在一个点歼解释器本身使用这种策略时具有嵌入的定义$:使用固定f..
鉴于您的使用3 : '?2',您似乎对匿名显式上下文感到满意.如果是这样的话,那么也许只是值得全力以赴,只是将原始的,未经改动的名词短语捕获为一个明确的动词:
meanConverge =: verb define
(+/%#) 0:`(>:@$:)@.(3 :'?2')"0 i. y
)
Run Code Online (Sandbox Code Playgroud)
但是,如果您更喜欢纯粹的默认解决方案,并希望在另一个方向上全力以赴,我们甚至可以消除3 : '?2'显式代码:
f =: mean @: converge @: i.
mean =: +/ % #
converge =: 0:`(>:@$:)@.(?@2:)"0
Run Code Online (Sandbox Code Playgroud)
而且,当然,有一些方法可以重写动词以完全避免递归,但这可能会破坏练习的目的.