作为J的初学者,我经常遇到隐性程序,与更熟悉的显式形式相比,这些程序看起来非常拜占庭。
现在只是因为我发现解释很难并不意味着默会形式不正确或错误。通常,隐性形式比显式形式短得多,因此更容易在视觉上同时看到所有形式。
专家提问:这些隐性形式是否传达了更好的结构感,并可能提炼出潜在的计算机制?还有其他好处吗?
我希望答案是肯定的,对于一些非平凡的例子也是如此......
答案 0 :(得分:7)
默认编程通常更快更有效,因为你可以告诉J你想要做什么,而不是让它在你的句子中找到它。但是,作为一个喜欢默契编程的人,我也可以说默认编程鼓励你以J的方式思考问题。
破坏结局并回答你的问题:是的,隐性编程可以并确实传达有关结构的信息。从技术上讲,它强调意义高于一切,但许多在你遇到的不那么简单的表达中占据显着位置的运算符(@: & &. ^:
仅举几例)具有非常结构相关的意思。
编写隐性代码的原因的典型示例是模幂运算的特殊代码,以及many more shortcuts like it的保证:
ts =: 6!:2, 7!:2@] NB. time and space
100 ts '2 (1e6&| @ ^) 8888x'
2.3356e_5 16640
100 ts '1e6 | 2 ^ 8888x'
0.00787232 8.496e6
您将听到的另一件重要事情是,当J看到一个明确的定义时,它必须在每次应用它时解析并评估它:
NB. use rank 0 to apply the verb a large number of times
100 ts 'i (4 : ''x + y + x * y'')"0 i=.i.100 100' NB. naive
0.0136254 404096
100 ts 'i (+ + *)"0 i=.i.100 100' NB. tacit
0.00271868 265728
NB. J is spending the time difference reinterpreting the definition each time
100 ts 'i (4 : ''x (+ + *) y'')"0 i=.i.100 100'
0.0136336 273024
但是,这两个原因都落后于 J具有非常独特的解决问题风格的想法。没有,如果有^:
。没有循环,有排名。同样地,Ken saw beauty在微积分中,f + g是函数的逐点和 - 实际上,将f + g定义为函数,其中(f + g)(x)= f(x)+ g(x) - 并且由于J在逐点数组加法方面已经非常出色,为什么还要停在那里?
正如像Haskell这样的语言在将高阶函数组合在一起而不是"手动"将它们端对端地同步,J也是如此。从语义上看,看看下面的例子:
h =: 3 : '(f y) + g y'
- h
是一个抓住其参数y
的函数,将其插入f
和g
,并将结果汇总为一个总和。 h =: f + g
- h
是函数f
和g
的总和。(A < B) +. (A = B)
- &#34; A小于B或A等于B.&#34; A (< +. =) B
- &#34; A小于或等于B.&#34; 它的代数更多。到目前为止,我只谈过火车;关于^:
或&.
等工具的便利性,还有很多话要说。但是,这一课程相当清楚:J希望能够以代数方式轻松地讨论您的函数。如果您必须将所有操作包装在3 :''
或4 :''
中 - 或者更糟,请将它们命名为单独的一行! - 每次您想要有趣地应用它们时(例如通过/
或^:
或;.
)你可能会被J关闭。
当然,我承认你很难找到像这些一样优雅的例子,因为你的表达变得更加复杂。默许风格只需要一些人习惯。词汇必须熟悉(如果不是第二天性)给你,即使这样,有时候你也有可能通过简单不可原谅的代码。任何语言都可能发生这种情况。
答案 1 :(得分:3)
不是专家,但对我来说默认编码的最大积极方面是1)它使编写程序的程序更容易编写程序,2)我更容易掌握J方式接近问题(这是为什么喜欢用J编程的一个重要部分)。显式感觉更像是程序编程,特别是如果我使用if.
,while.
或select.
等控制字。
挑战在于:1)显式代码有时比默认运行得更快,但这取决于任务和算法; 2)默认代码在解析时被解释,这意味着有时显式代码更清晰因为您可以让代码等待仅在运行时定义的变量值。