【问题标题】:J: Why does `f^:proposition^:_ y` stand for a while loop?J:为什么`f^:proposition^:_y`代表一个while循环?
【发布时间】:2013-09-12 00:11:08
【问题描述】:

正如标题所说,我不明白为什么f^:proposition^:_ y 是一个while 循环。我实际上已经使用了几次,但我不明白它是如何工作的。我知道^: 重复功能,但我对该语句中的双重使用感到困惑。

我也不明白为什么f^:proposition^:a: y 有效。这与前一个相同,但返回所有迭代的值,而不是像上面那样只返回最后一个。

a: 是一个空框,我知道它与^: 一起使用具有特殊含义,但即使查了字典我也无法理解。

谢谢。

【问题讨论】:

    标签: while-loop j


    【解决方案1】:

    f^:proposition^:_ 不是 while 循环。当proposition 返回10 时,它(几乎) 是一个while 循环。当proposition 返回其他结果时,这是一种奇怪的while 循环。

    让我们来看一个简单的单子案例。

    f =: +:        NB. Double
    v =: 20 > ]    NB. y less than 20
    
    (f^:v^:_) 0     NB. steady case
    0
    (f^:v^:_) 1     NB. (f^:1) y, until (v y) = 0
    32
    (f^:v^:_) 2
    32
    (f^:v^:_) 5
    20
    (f^:v^:_) 21   NB. (f^:0) y
    21
    

    这就是正在发生的事情:每次v y1(f^:1) y 都会被执行。 (f^:1) y 的结果是新的y 等等。

    • 如果y连续两次保持不变→输出y并停止。
    • 如果v y0→ 输出y 并停止。

    所以这里是f^:v^:_,就像double while less than 20 (or until the result doesn't change)一样工作

    让我们看看当v 返回2/0 而不是1/0 时会发生什么。

     v =: 2 * 20 > ]
    
    (f^:v^:_) 0      NB. steady state
    0
    (f^:v^:_) 1      NB. (f^:2) 1 = 4 -> (f^:2) 4 = 16 -> (f^:2) 16 = 64 [ -> (f^:0) 64 ]
    64
    (f^:v^:_) 2      NB. (f^:2) 2 = 8 -> (f^:2) 8 = 32 [ -> (f^:0) 32 ]
    32
    (f^:v^:_) 5      NB. (f^:2) 5 = 20 [ -> (f^:0) 20 ]
    20
    (f^:v^:_) 21     NB. [ (f^:0) 21 ]
    21
    

    您可以通过v 玩多种“奇怪的”循环。 (它甚至可以返回负整数,使用 f 的倒数)。

    【讨论】:

    • 谢谢!你的最后一句话启发了我!所以v 的结果指定了重复f 的次数(如果它是负数,你得到f 的倒数)。完美的!我也明白为什么a: 可以再次阅读字典。基本上,对于某个整数k,它会转换为f^:i.k,这就是为什么你会得到多个结果:一个数组被传递给^:
    【解决方案2】:

    Excerpted and adapted from a longer writeup I posted to the J forums in 2009:

    while =:  ^:break_clause^:_
    

    这是一个可以应用于任何代码的副词(相当于 循环体)来创建一个while循环。如果您以前没有见过,^: 是电源连接。更具体地说,短语f^:n y 将函数f 应用于参数y 恰好n 次。计数n 可能是一个整数或应用于y 的函数会产生一个整数¹。

    在上面的副词中,我们看到了两次幂连词,一次在^:break_clause,另一次在^:_ 。我们先讨论后者。 _ 是 J 的无穷大符号。所以,从字面上看,^:_ 是“无限次地应用函数”或“永远重新应用”。这与 while 循环的功能有关,但如果按字面应用,它并不是很有用。

    因此,相反,^:_ 及其近亲被定义为“将函数应用到其极限”,即“继续应用该函数直到其输出与输入匹配”。在这种情况下,再次应用该函数将无效,因为下一次迭代将具有与前一次相同的输入(请记住,J 是一种函数式语言)。所以有 再次应用该功能毫无意义:它已达到其极限。

    例如:

       cos=:  2&o.   NB. Cosine function
       pi =:  1p1    NB. J's notation for 1*pi^1 analogous to scientific notation 1e1
    
       cos pi
    _1
       cos cos cos pi
    0.857553
       cos^:3 pi
    0.857553
       cos^:10 pi
    0.731404
       cos^:_ pi  NB.  Fixed point of cosine
    0.739085
    

    在这里,我们一直应用余弦,直到答案停止变化:余弦已达到其固定点,更多的应用是多余的。我们可以通过显示 中间步骤:

       cos^:a: pi
    3.1415926535897 _1 0.54030230586813 ...73 more... 0.73908513321512 0.73908513321
    

    所以^:_ 将函数应用到其极限。好的,^:break_condition 呢?同样,这是相同的概念:将左侧函数应用到右侧函数指定的次数。在_ (或其等效函数_: )的情况下,输出为“无穷大”,在break_condition 的情况下,输出将为01,具体取决于输入(中断条件是布尔值)。

    因此,如果输入是“正确的”(即处理完成),那么 break_condition 将是 0,因此 loop_body^:break_condition^:_ 将变为 loop_body^:0^:_ 。显然,loop_body^:0 应用了 loop_body 零次,没有任何效果。

    “没有效果”是保持输入不变;换句话说,它将输入复制到输出......但是如果输入与输出匹配,则函数已达到其极限!显然^:_: 检测到这一事实并终止。瞧,一个while循环!


    ¹ 是的,包括零整数和负整数,并且“整数”应该更恰当地理解为“任意整数数组”(因此该函数可以同时应用于多个幂)。

    【讨论】:

    • 如果 f^: 的整数参数是 _1 ...你得到函数 f 的逆。定义函数逆的快速方法!
    • 谢谢!很好的解释,你提供的链接也很有趣。
    猜你喜欢
    • 2011-08-20
    • 2021-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-12
    • 2018-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多