阅读 J 代码的最佳策略

发布于 2024-08-30 16:55:46 字数 806 浏览 9 评论 0原文

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

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

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

3) 将每个运算符替换为它的值词汇页中的口头描述

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

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

6) 写下 (5) 中每个组件的含义的描述do,用简单的英语散文

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

8) 写出一个解释,说明为什么 (1) 中的代码可以说代表了 (7) 中的设计概念)。

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

编辑:

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

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

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

I've been using J for a few months now, and I find that reading unfamiliar code (e.g. that I didn't write myself) is one of the most challenging aspects of the language, particularly when it's in tacit. After a while, I came up with this strategy:

1) Copy the code segment into a word document

2) Take each operator from (1) and place it on a separate line, so that it reads vertically

3) Replace each operator with its verbal description in the Vocabulary page

4) Do a rough translation from J syntax into English grammar

5) Use the translation to identify conceptually related components and separate them with line breaks

6) Write a description of what each component from (5) is supposed to do, in plain English prose

7) Write a description of what the whole program is supposed to do, based on (6)

8) Write an explanation of why the code from (1) can be said to represent the design concept from (7).

Although I learn a lot from this process, I find it to be rather arduous and time-consuming -- especially if someone designed their program using a concept I never encountered before. So I wonder: do other people in the J community have favorite ways to figure out obscure code? If so, what are the advantages and disadvantages of these methods?

EDIT:

An example of the sort of code I would need to break down is the following:

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

I wrote this one myself, so I happen to know that it takes a numerical input, reinterprets it as a ternary array and interprets the result as the representation of a number in base-2 with at most one duplication. (e.g., binconv 5 = (3^1)+2*(3^0) -> 1 2 -> (2^1)+2*(2^0) = 4.) But if I had stumbled upon it without any prior history or documentation, figuring out that this is what it does would be a nontrivial exercise.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

二手情话 2024-09-06 16:55:46

只是想添加到 Jordan's Answer :如果您没有打开框显示,则可以使用 5!:2 以这种方式明确格式化内容。

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

还有一个树形显示:

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

请参阅词汇表页面 5!: 表示 以及 9!: 用于更改默认值的全局参数

另外,就其价值而言,我自己阅读 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

Just wanted to add to Jordan's Answer : if you don't have box display turned on, you can format things this way explicitly with 5!:2

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

There's also a tree display:

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

See the vocabulary page for 5!: Representation and also 9!: Global Parameters for changing the default.

Also, for what it's worth, my own approach to reading J has been to retype the expression by hand, building it up from right to left, and looking up the pieces as I go, and using identity functions to form temporary trains when I need to.

So for example:

   /:~ 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!

addendum:

   NB. just to be clear:
   f 'drara' NB. should also return 'd' because it sorts first
d
俏︾媚 2024-09-06 16:55:46

首先尝试将动词分解为各个组成部分,然后看看它们的作用。您不必总是参考词汇,您可以简单地尝试数据上的一个组件,看看它的作用,看看您是否能弄清楚它。要查看动词的结构,有助于了解您正在查看的词性,以及如何识别叉子等基本结构(当然,在较大的默认结构中,用括号分隔)。只需在 ijx 窗口中输入动词并按 Enter 键也会分解结构,并且可能会有所帮助。

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

我知道 <. -: # {/: 都是动词,~ 是副词,@ 是连词(参见词汇中的词性链接)。因此我可以看到这是一个带有左动词 <.@-:@# 、右动词 /:~ 和二元 { .这需要一些练习才能看到,但有一种更简单的方法,让 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 的知识。我想我建议集中精力尝试查看语法结构,然后找出各个部分,逐步构建它(因为这就是您最终编写默会动词的方式)。

Try breaking the verb up into its components first, and then see what they do. And rather than always referring to the vocab, you could simply try out a component on data to see what it does, and see if you can figure it out. To see the structure of the verb, it helps to know what parts of speech you're looking at, and how to identify basic constructions like forks (and of course, in larger tacit constructions, separate by parentheses). Simply typing the verb into the ijx window and pressing enter will break down the structure too, and probably help.

Consider the following simple example: <.@-:@#{/:~

I know that <. -: # { and /: are all verbs, ~ is an adverb, and @ is a conjunction (see the parts of speech link in the vocab). Therefore I can see that this is a fork structure with left verb <.@-:@# , right verb /:~ , and dyad { . This takes some practice to see, but there is an easier way, let J show you the structure by typing it into the ijx window and pressing enter:

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

Here you can see the structure of the verb (or, you will be able to after you get used to looking at these). Then, if you can't identify the pieces, play with them to see what they do.

   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

You can break them down further and experiment as needed to figure them out (this little example is a median verb).

J packs a lot of code into a few characters and big tacit verbs can look very intimidating, even to experienced users. Experimenting will be quicker than your documenting method, and you can really learn a lot about J by trying to break down large complex verbs. I think I'd recommend focusing on trying to see the grammatical structure and then figure out the pieces, building it up step by step (since that's how you'll eventually be writing tacit verbs).

近箐 2024-09-06 16:55:46

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

我刚刚在 jsoftware 网站 与乔丹的答案和我在问题中描述的方法结合得很好。作者提出了一些中肯的观点:

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

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

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

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

[: +/\

{.@] ,

>:@[ #

(}.-}:)@] %

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

    (右上参数)解开

    (左参数上方增量)计数

    (砍头减去削减)右上角
    论据

    除以

    左上参数增量

  • 序列的部分和
    定义为

    正确参数的第一项,
    一起狂欢

    (一加上左边的参数)复制

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

    右参数除以

    (一加上左边的参数)。

  • 序列的部分和
    定义为

    从相同的初始点开始,

    并附加连续的副本
    从正确的论证中得出的点

    从其前任值中减去每个前任者
    继任者

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

  • 在之间插入 x 个值
    y 的项目

(I'm putting this in the answer section instead of editing the question because the question looks long enough as it is.)

I just found an excellent paper on the jsoftware website that works well in combination with Jordan's answer and the method I described in the question. The author makes some pertinent observations:

1) A verb modified by an adverb is a verb.

2) A train of more than three consecutive verbs is a series of forks, which may have a single verb or a hook at the far left-hand side depending on how many verbs there are.

This speeds up the process of translating a tacit expression into English, since it lets you group verbs and adverbs into conceptual units and then use the nested fork structure to quickly determine whether an instance of an operator is monadic or dyadic. Here's an example of a translation I did using the refined method:

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

[: +/\

{.@] ,

>:@[ #

(}.-}:)@] %

>:@[
  • cap (plus infix prefix)

    (head atop right argument) ravel

    (increment atop left argument) tally

    (behead minus curtail) atop right
    argument

    divided by

    increment atop left argument

  • the partial sums of the sequence
    defined by

    the first item of the right argument,
    raveled together with

    (one plus the left argument) copies
    of

    (all but the first element) minus
    (all but the last element)

    of the right argument, divided by

    (one plus the left argument).

  • the partial sums of the sequence
    defined by

    starting with the same initial point,

    and appending consecutive copies of
    points derived from the right argument by

    subtracting each predecessor from its
    successor

    and dividing the result by the number
    of copies to be made

  • Interpolating x-many values between
    the items of y
千と千尋 2024-09-06 16:55:46

我只想谈谈我的阅读方式:
<.@-:@#{/:~

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

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

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

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

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

做中间动词。

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

I just want to talk about how I read:
<.@-:@#{/:~

First off, I knew that if it was a function, from the command line, it had to be entered (for testing) as

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

Now I looked at the stuff in the parenthesis. I saw a /:~, which returns a sorted list of its arguments, { which selects an item from a list, # which returns the number of items in a list, -: half, and <., floor...and I started to think that it might be median, - half of the number of items in the list rounded down, but how did # get its arguments? I looked at the @ signs - and realized that there were three verbs there - so this is a fork. The list comes in at the right and is sorted, then at the left, the fork got the list to the # to get the number of arguments, and then we knew it took the floor of half of that. So now we have the execution sequence:

sort, and pass the output to the middle verb as the right argument.

Take the floor of half of the number of elements in the list, and that becomes the left argument of the middle verb.

Do the middle verb.

That is my approach. I agree that sometimes the phrases have too many odd things, and you need to look them up, but I am always figuring this stuff out at the J instant command line.

贩梦商人 2024-09-06 16:55:46

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

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

通读这里的规定,我发现这与其他人使用该语言的方式没有太大不同。

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

Personally, I think of J code in terms of what it does -- if I do not have any example arguments, I rapidly get lost. If I do have examples, it's usually easy for me to see what a sub-expression is doing.

And, when it gets hard, that means I need to look up a word in the dictionary, or possibly study its grammar.

Reading through the prescriptions here, I get the idea that this is not too different from how other people work with the language.

Maybe we should call this 'Test Driven Comprehension'?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文