隐性编程通常更快更高效,因为你可以准确地告诉 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) – “A 小于 B 或 A 等于 B。”
-
A (< +. =) B – “A 小于或等于 B。”
代数要多得多。到目前为止,我只谈到了火车;关于^: 或&. 等工具的易用性,有很多话要说。不过,这个教训是相当清楚的:J 希望用代数方式轻松地谈论你的函数。如果您必须将所有操作包装在 3 :'' 或 4 :'' 中——或者更糟,将它们命名在单独的行中!——每次你想有趣地应用它们时(例如通过 / 或 ^: 或 @987654344 @) 你可能对 J 很反感。
当然,我承认随着您的表达变得越来越复杂,您将很难找到像这些优雅的示例。默契的风格只是需要一些时间来适应。您必须熟悉词汇(如果不是第二天性的话),即便如此,有时您也会乐于在无法原谅的代码中苦苦挣扎。任何语言都可能发生这种情况。