J语言。我想要以函数形式表达结果

J language. I want express result in form of function

(+/%#)0:`(>:@$:)@.(3 :'?2')"0 i.10000

如我所想的那样工作。 答案倾向于1。 现在我想用

的形式表达这个结果
f =: (+/%#)0:`(>:@$:)@.(3 :'?2')"0 i.
f 10000

无效。

隐式与显式组合

通过 J 中的并列将几个动词串在一起并不会创建管道,它会创建一个具有不同语义的“verb train”。

名词短语:

foo bar bar buz 10000

不同于动词短语:

f =: foo bar baz buz
f 10000

如果你想要一个动词管道,你必须使用某种形式的 explicit composition(即表示,而不是暗示)。

最常见的是,管道由一元动词组成(将一个输入转换为一个输出,成为下一个动词的输入),因此我们使用@:(或@,但使用这需要更多地关注细节),因此与原始名词短语的口头等价物是:

f =: foo @: bar @: baz @: buz
f 10000

组合和匿名递归

鉴于您的情况,我们可能会天真地写成:

(+/%#) @: (0:`(>:@$:)@.(3 :'?2')"0) @: i.

注意将中间动词 (0:`(>:@$:)@.(3 :'?2')"0) 括在括号中,因为我们想应用那个动词,并且只应用那个动词,排名为零 ("0),特别是应用整个结果的平均值 (+/ % #),而不是每个结果的平均值。

但是如果我们这样做,并且运行它,我们很快就会运行陷入一个问题:无限递归

在原始名词短语中,动词 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

,因为它隔离了 $:,确保它只引用 converge

同样,您可以将 $: 嵌入匿名显式上下文中,从本质上限制其权限:

f =:  (+/%#) @: (verb def '0:`(>:@$:)@.(3 :'?2')"0 y') @: i.

这就像给 $: 戴上眼罩:现在它看不到 verb def 外面了。一些默认的纯粹主义者可能会对这种方法犹豫不决,但在某一时刻 the J interpreter itself employed this tactic 当使用 f..

修复带有嵌入式 $: 的定义时

解决方案

鉴于您对 3 : '?2' 的使用,您似乎对匿名显式上下文感到满意。如果是这样的话,那么也许值得全力以赴,将原始的、未改变的名词短语捕获为显式动词:

meanConverge =: verb define
   (+/%#) 0:`(>:@$:)@.(3 :'?2')"0 i. y
)

但是,如果您更喜欢纯粹的默认解决方案,并且想在 其他 方向上全力以赴,我们甚至可以消除 3 : '?2' 显式代码:

f          =:  mean @: converge @: i.
  mean     =:  +/ % #
  converge =:  0:`(>:@$:)@.(?@2:)"0

当然,还有一些方法可以重写动词来完全避免递归,但这可能会违背练习的目的。