(+/%#)0:`(>:@$:)@.(3 :'?2')"0 i.10000
工作,我想。答案趋向于1。现在我想用
的形式来表示这个结果f =: (+/%#)0:`(>:@$:)@.(3 :'?2')"0 i.
f 10000
行不通。
隐式与显式合成
在J中通过并置将几个动词串在一起不会创建一个管道,它创建了一个"动词序列",具有不同的语义。
即名词短语:
foo bar bar buz 10000
不同于动词短语:
f =: foo bar baz buz
f 10000
如果你想要一个动词管道,你必须使用某种形式的显式组合(即表示,而不是暗示)。
最常见的是,管道由单复数动词组成(将一个输入转换为一个输出,它成为下一个动词的输入),所以我们使用@:
(或@
,但使用它需要更注意细节),因此与原始名词短语等价的动词将是:
f =: foo @: bar @: baz @: buz
f 10000
复合和匿名递归
考虑到这一点,在你的情况下,我们可能会天真地写:
(+/%#) @: (0:`(>:@$:)@.(3 :'?2')"0) @: i.
注意将中间的动词(0:`(>:@$:)@.(3 :'?2')"0
)包在括号中,因为我们想要应用该动词,并且只应用该动词,在第0级("0
),特别是将平均值(+/ % #
)应用于整个结果,而不是每个单独的结果。
但是如果我们这样做并运行它,我们很快就会遇到一个问题:无限递归。
在原名词短语中,动词0:`(>:@$:)@.(3 :'?2')"0
单独存在,因此该动词中的$:
(匿名递归)指代0:`(>:@$:)@.(3 :'?2')"0
,仅指代0:`(>:@$:)@.(3 :'?2')"0
。
然而,一旦我们将三个动词的序列重新制定为一个管道(f
,上文),那么$:
就嵌入到f
中,因此指的是f
。
意思是,在f
的这个公式中,当$:
递归到一个1上时,首先,i.
被应用到这个1上,得到,0
,然后?
产生一个随机比特,它有50%的概率是1,然后$:
递归到这个1上,i.
被应用到....
这是一个在j中很常见的陷阱。
隔离$:
你可以把你的代码分成更小的,命名的片段:
f =: mean @: converge @: i.
mean =: +/ % #
converge =: 0:`(>:@$:)@.(3 :'?2')"0
,因为它隔离了$:
,所以确保它只引用converge
。
同样,您可以将$:
嵌入到一个匿名显式上下文中,本质上限制了它的权限:
f =: (+/%#) @: (verb def '0:`(>:@$:)@.(3 :'?2')"0 y') @: i.
这就像给$:
戴上眼罩:现在它看不到verb def
外面了。一些默认的纯粹主义者可能会对这种方法犹豫不决,但是当使用f.
来固定带有嵌入式$:
的定义时,J解释器本身曾经使用过这种策略。
鉴于您使用3 : '?2'
,您似乎对匿名显式上下文感到满意。如果是这样的话,那么也许值得全力以赴,将原始的、未经修改的名词短语作为明确的动词使用:
meanConverge =: verb define
(+/%#) 0:`(>:@$:)@.(3 :'?2')"0 i. y
)
但是,如果你更喜欢一个纯粹的隐性解决方案,并且想要完全在其他方向上,我们甚至可以消除3 : '?2'
显式代码:
f =: mean @: converge @: i.
mean =: +/ % #
converge =: 0:`(>:@$:)@.(?@2:)"0
当然,有一些方法可以重写动词来完全避免递归,但这可能违背了练习的目的。