5

作为 JI 的初学者,经常会遇到与更熟悉的显式形式相比显得相当拜占庭式的默认程序。

现在,仅仅因为我发现很难解释并不意味着默认形式是错误的或错误的。很多时候,默认形式比显式形式要短得多,因此更容易在视觉上一次看到所有内容。

向专家提问:这些隐性形式是否传达了更好的结构感,并可能提炼出潜在的计算机制?还有其他好处吗?

我希望答案是肯定的,并且对于一些不平凡的例子来说是正确的......

4

2 回答 2

7

隐性编程通常更快更有效,因为你可以准确地告诉 J 你想做什么,而不是让它随着你的句子而发现。但是作为一个非常喜欢隐性编程的人,我也可以说隐性编程鼓励你以 J 方式思考事物

破坏结局并回答您的问题:是的,隐性编程可以并且确实传达了有关结构的信息。从技术上讲,它强调意义高于一切,但许多在您将遇到的不那么琐碎的表达式中突出显示的运算符(@: & &. ^:仅举几例)具有非常与结构相关的含义。

编写默认代码的典型例子是模幂运算的特殊代码,以及有更多类似它的快捷方式的保证:

   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 看到了这样一个事实,即在微积分中,f+g 是函数的逐点和——事实上,人们将 f+g 定义为函数,其中 (f+g)(x) = f(x) + g( x)——既然 J 已经非常擅长逐点数组加法,为什么要停在那里呢?

正如像 Haskell 这样的语言喜欢将高阶函数组合在一起而不是“手动”将它们端到端同步,J. Semantically 也是如此,请看以下示例:

  • h =: 3 : '(f y) + g y'h是一个函数,它获取其参数y,将其插入fand g,并将结果汇​​集到一个 sum 中。
  • h =: f + gh是函数f和的总和g
  • (A < B) +. (A = B)– “A 小于 B 或 A 等于 B。”
  • A (< +. =) B– “A 小于或等于 B。”

它更代数。到目前为止,我只谈到了火车;关于^:&.. 不过,这个教训是相当清楚的:J 希望用代数方式轻松讨论你的函数。如果您必须将所有操作都包含在3 :''or中4 :''——或者更糟糕的是,将它们命名在单独的行中!——每次你想有趣地应用它们(比如 via/^:or ;.)时,你可能会非常不喜欢 J。

当然,我承认当你的表达变得越来越复杂时,你将很难找到像这些优雅的例子。默契的风格只是需要一些时间来适应。您必须熟悉词汇(如果不是第二天性的话),即便如此,有时您也会乐于在无法原谅的代码中苦苦挣扎。任何语言都可能发生这种情况。

于 2015-04-14T06:36:44.873 回答
3

不是专家,但对我来说,默认编码的最大积极方面是 1)它使编写程序更容易编写程序,以及 2)我更容易掌握处理问题的 J 方式(这是为什么喜欢用 J 编程的重要部分)。Explicit 感觉更像是过程编程,尤​​其是当我使用控制字时,例如if.,while.select..

挑战在于:1)显式代码有时比默认代码运行得更快,但这取决于任务和算法;2)默认代码在解析时被解释,这意味着有时显式代码更干净,因为你可以让代码等待仅在运行时定义的变量值。

于 2015-04-12T17:07:01.660 回答