J语言.我希望以功能的形式表达结果

Rom*_*man 3 j

(+/%#)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)

不行.

Dan*_*ron 5

隐式与显式组合

通过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)

而且,当然,有一些方法可以重写动词以完全避免递归,但这可能会破坏练习的目的.