14

我已经使用 J 几个月了,我发现阅读不熟悉的代码(例如,我不是自己编写的)是该语言最具挑战性的方面之一,尤其是当它处于默认状态时。一段时间后,我想出了这个策略:

1)将代码段复制到word文档中

2)从(1)中取出每个运算符并将其放在单独的行上,以便垂直读取

3) 用词汇页面中的语言描述替换每个运算符

4)从J语法粗略翻译成英语语法

5) 使用翻译来识别概念上相关的组件并用换行符分隔它们

6)用简单的英语散文描述(5)中的每个组件应该做什么

7) 根据 (6) 写出整个程序应该做什么的描述

8) 解释为什么(1)中的代码可以说代表(7)中的设计概念。

虽然我从这个过程中学到了很多东西,但我发现它相当费力和耗时——尤其是如果有人使用我以前从未遇到过的概念来设计他们的程序。所以我想知道:J 社区中的其他人是否有最喜欢的方式来找出晦涩的代码?如果是这样,这些方法的优点和缺点是什么?

编辑:

我需要分解的代码示例如下:

binconv =: +/@ ((|.@(2^i.@#@])) * ]) @ ((3&#.)^:_1)

我自己写了这个,所以我碰巧知道它需要一个数字输入,将其重新解释为三元数组,并将结果解释为以 base-2 表示的数字,最多有一个重复。(例如,binconv 5 = (3^1)+2*(3^0) -> 1 2 -> (2^1)+2*(2^0) = 4。)但是如果我偶然发现它没有任何先前的历史或文档,弄清楚这就是它所做的事情将是一项不平凡的工作。

4

5 回答 5

13

只是想添加到乔丹的答案:如果你没有打开盒子显示,你可以用这种方式明确地格式化东西5!:2

   f =. <.@-:@#{/:~
   5!:2 < 'f'
┌───────────────┬─┬──────┐
│┌─────────┬─┬─┐│{│┌──┬─┐│
││┌──┬─┬──┐│@│#││ ││/:│~││
│││&lt;.│@│-:││ │ ││ │└──┴─┘│
││└──┴─┴──┘│ │ ││ │      │
│└─────────┴─┴─┘│ │      │
└───────────────┴─┴──────┘

还有一个树显示:

   5!:4 <'f'
              ┌─ <.
        ┌─ @ ─┴─ -:
  ┌─ @ ─┴─ #       
──┼─ {             
  └─ ~ ─── /:     

参见词汇页面5!: Representation9!: Global Parameters以更改默认值。

此外,对于它的价值,我自己阅读 J 的方法是手动重新输入表达式,从右到左构建它,并在我去的时候查找碎片,并在需要时使用恒等函数形成临时火车至。

例如:

   /:~ i.5
0 1 2 3 4
   NB. That didn't tell me anything
   /:~ 'hello'
ehllo
   NB. Okay, so it sorts. Let's try it as a train:
   [ { /:~ 'hello'
┌─────┐
│ehllo│
└─────┘
   NB. Whoops. I meant a train:
   ([ { /:~) 'hello'
|domain error
|       ([{/:~)'hello'
   NB. Not helpful, but the dictionary says
   NB. "{" ("From") wants a number on the left.
   (0: { /:~) 'hello'
e
   (1: { /:~) 'hello'
h
   NB. Okay, it's selecting an item from the sorted list.
   NB. So f is taking the ( <. @ -: @ # )th item, whatever that means...
   <. -: # 'hello'
2
   NB. ??!?....No idea. Let's look up the words in the dictionary.
   NB. Okay, so it's the floor (<.) of half (-:) the length (#)
   NB. So the whole phrase selects an item halfway through the list.
   NB. Let's test to make sure.
   f 'radar' NB. should return 'd'
d
   NB. Yay!

附录:

   NB. just to be clear:
   f 'drara' NB. should also return 'd' because it sorts first
d
于 2013-10-25T06:01:18.890 回答
11

试着先把动词分解成它的组成部分,然后看看它们做了什么。而不是总是提到词汇,你可以简单地尝试一个数据组件,看看它做了什么,看看你是否能弄明白。要查看动词的结构,有助于了解您正在查看的词性,以及如何识别叉子等基本结构(当然,在较大的默示结构中,用括号分隔)。只需在 ijx 窗口中键入动词并按 Enter 键也会破坏结构,并且可能会有所帮助。

考虑以下简单示例:<.@-:@#{/:~

我知道<. -: # {and/:都是动词,~是副词,@是连词(参见词汇中的词性链接)。因此我可以看到这是一个带有左动词<.@-:@#、右动词/:~和二元组的分叉结构{。这需要一些练习才能看到,但有一种更简单的方法,让 J 通过在 ijx 窗口中键入结构并按 Enter 键向您展示结构:

   <.@-:@#{/:~
+---------------+-+------+
|+---------+-+-+|{|+--+-+|
||+--+-+--+|@|#|| ||/:|~||
|||<.|@|-:|| | || |+--+-+|
||+--+-+--+| | || |      |
|+---------+-+-+| |      |
+---------------+-+------+

在这里您可以看到动词的结构(或者,在您习惯看这些之后,您将能够看到)。然后,如果您无法识别这些碎片,请与它们一起玩,看看它们做了什么。

   10?20
15 10 18 7 17 12 19 16 4 2
   /:~ 10?20
1 4 6 7 8 10 11 15 17 19
   <.@-:@# 10?20
5

您可以进一步分解它们并根据需要进行实验以找出它们(这个小例子是中间动词)。

J 将大量代码打包成几个字符,大的默认动词看起来非常吓人,即使对于有经验的用户也是如此。实验会比你的记录方法更快,你可以通过尝试分解大型复杂动词来真正学到很多关于 J 的知识。我想我建议专注于尝试查看语法结构,然后找出碎片,逐步构建它(因为这就是你最终会写出默示动词的方式)。

于 2010-05-05T22:22:55.570 回答
3

(我将其放在答案部分而不是编辑问题,因为问题看起来足够长。)

我刚刚在jsoftware 网站上找到了一篇优秀的论文,它与 Jordan 的答案和我在问题中描述的方法相结合,效果很好。作者提出了一些中肯的意见:

1)由副词修饰的动词是动词。

2)超过三个连续动词的序列是一系列叉子,根据动词的数量,它可能有一个动词或最左边的一个钩子。

这加快了将默认表达式翻译成英语的过程,因为它可以让您将动词和副词分组为概念单元,然后使用嵌套的分叉结构来快速确定运算符的实例是一元还是二元。这是我使用精炼方法进行的翻译示例:

d28=: [:+/\{.@],>:@[#(}.-}:)@]%>:@[

[: +/\

{.@] ,

>:@[ #

(}.-}:)@] %

>:@[
  • 上限(加上中缀前缀)

    (右上论点) ravel

    (左上角自增)计数

    (斩首减去削减)右上角的论点

    除以

    在左参数上递增

  • 由定义的序列的部分和

    正确论证的第一项,与

    (一加左参数)副本

    (除第一个元素之外的所有元素)减去(除最后一个元素之外的所有元素)

    的正确论点,除以

    (一加左参数)。

  • 由定义的序列的部分和

    从相同的初始点开始,

    并附加从正确参数派生的点的连续副本

    从其后继中减去每个前任

    并将结果除以要制作的副本数

  • 在 y 的项目之间插入 x-many 值
于 2010-05-23T11:22:15.643 回答
2

我只想说说我是怎么读的:<.@-:@#{/:~

首先,我知道如果它是一个函数,从命令行,它必须输入(用于测试)为

(<.@-:@#{/:~)

现在我查看了括号中的内容。我看到了一个 /:~,它返回一个排序的参数列表,{ 从列表中选择一个项目,# 返回列表中的项目数,-: half 和 <., floor...我开始认为它可能是中位数,- 列表中项目数的一半向下舍入,但 # 是如何得到它的论点的呢?我看着@符号——意识到那里有三个动词——所以这是一个叉子。列表从右侧进入并排序,然后在左侧,fork 将列表带到 # 以获取参数的数量,然后我们知道它占用了一半的地板。所以现在我们有了执行顺序:

排序,并将输出作为正确的参数传递给中间动词。

取列表中元素数量的一半,这成为中间动词的左参数。

做中间动词。

这就是我的方法。我同意有时这些短语有太多奇怪的东西,你需要查找它们,但我总是在 J 即时命令行中找出这些东西。

于 2011-11-01T01:39:30.480 回答
1

就个人而言,我从 J 代码的作用来考虑它——如果我没有任何示例参数,我很快就会迷失方向。如果我确实有示例,我通常很容易看到子表达式在做什么。

而且,当它变得困难时,这意味着我需要在字典中查找一个单词,或者可能研究它的语法。

通读这里的处方,我觉得这与其他人使用该语言的方式没有太大区别。

也许我们应该称之为“测试驱动理解”?

于 2011-02-24T13:08:31.240 回答