我已经使用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.)但如果我偶然发现它没有任何先前的历史或文件,弄清楚它的作用将是一项非常重要的练习。
答案 0 :(得分:10)
只想添加到Jordan's Answer:如果您没有启用框显示,则可以使用5!:2
f =. <.@-:@#{/:~
5!:2 < 'f'
┌───────────────┬─┬──────┐
│┌─────────┬─┬─┐│{│┌──┬─┐│
││┌──┬─┬──┐│@│#││ ││/:│~││
│││<.│@│-:││ │ ││ │└──┴─┘│
││└──┴─┴──┘│ │ ││ │ │
│└─────────┴─┴─┘│ │ │
└───────────────┴─┴──────┘
还有一个树形显示:
5!:4 <'f'
┌─ <.
┌─ @ ─┴─ -:
┌─ @ ─┴─ #
──┼─ {
└─ ~ ─── /:
请参阅5!: Representation的词汇表页面以及更改默认值的9!: 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
答案 1 :(得分:9)
首先尝试将动词分解为其组件,然后查看它们的作用。而不是总是提到词汇,你可以简单地尝试一个数据组件,看看它做了什么,看看你是否可以搞清楚。要查看动词的结构,有助于了解您正在查看的词性,以及如何识别叉子等基本结构(当然,在较大的隐性结构中,用括号分开)。只需在ijx窗口中键入动词并按Enter即可细分结构,并可能有所帮助。
请考虑以下简单示例:<.@-:@#{/:~
我知道<.
-:
#
{
和/:
都是动词,~
是副词,{{1}是一个连词(见词汇中的词性链接)。因此,我可以看到这是一个包含左动词@
,右动词<.@-:@#
和dyad /:~
的分叉结构。这需要一些练习才能看到,但有一种更简单的方法,让J通过在ijx窗口中键入并按下回车来显示结构:
{
在这里你可以看到动词的结构(或者,你可以在习惯看这些之后)。然后,如果你不能识别这些碎片,可以和它们一起玩,看看它们是做什么的。
<.@-:@#{/:~
+---------------+-+------+
|+---------+-+-+|{|+--+-+|
||+--+-+--+|@|#|| ||/:|~||
|||<.|@|-:|| | || |+--+-+|
||+--+-+--+| | || | |
|+---------+-+-+| | |
+---------------+-+------+
你可以进一步细分它们并根据需要进行实验来计算它们(这个小例子是一个中值动词)。
J将大量代码打包成几个字符,大型默认动词看起来非常令人生畏,即使对于有经验的用户也是如此。尝试将比你的记录方法更快,你可以通过尝试分解大型复杂动词来学到很多关于J的知识。我想我会建议专注于尝试查看语法结构,然后弄清楚各个部分,逐步建立起来(因为这就是你最终会如何编写隐性动词)。
答案 2 :(得分:3)
(我把它放在答案部分,而不是编辑问题,因为这个问题看起来很长。)
我刚刚发现了一篇关于the jsoftware website的优秀论文,它与乔丹的回答以及我在问题中描述的方法相结合。作者提出了一些相关的意见:
1)由副词修饰的动词是动词。
2)一列三个以上连续动词是一系列的分叉,在最左边可能有一个动词或一个钩子,具体取决于动词的数量。
这加快了将默认表达式翻译成英语的过程,因为它允许您将动词和副词分组为概念单元,然后使用嵌套的fork结构快速确定运算符的实例是monadic还是二元。这是我使用精炼方法进行翻译的一个例子:
d28=: [:+/\{.@],>:@[#(}.-}:)@]%>:@[
[: +/\
{.@] ,
>:@[ #
(}.-}:)@] %
>:@[
上限(加上中缀前缀)
(在右上角的争论中)ravel
(增加左上角参数)理货
在右边的(斩首减去缩减) 参数
除以
在左参数上增加
序列的部分和 由
定义正确论证的第一项, 与
一起肆虐(一加左参数)复制 的
(除了第一个元素之外的所有元素)减去 (除最后一个元素外)
正确论证的除以
(一加左参数)。
序列的部分和 由
定义从相同的初始点开始,
并附加连续的副本
从正确的论点派生的点数从其中减去每个前任 后继
并将结果除以数字 要制作的副本
答案 3 :(得分:1)
我个人认为J代码就它的作用而言 - 如果我没有任何示例参数,我会很快迷失方向。如果我有例子,我通常很容易看到子表达式正在做什么。
而且,当它变得困难时,这意味着我需要在字典中查找一个单词,或者可能研究它的语法。
通过阅读这里的处方,我认为这与其他人使用该语言的方式并无太大差别。
也许我们应该称之为'测试驱动的理解'?
答案 4 :(得分:1)
我只是想谈谈我的阅读方式: &LT; @ - :@#{/:〜
首先,我知道如果它是一个函数,从命令行开始,必须输入(用于测试)
(小于@ - :@#{/:〜)
现在我查看了括号中的内容。我看到了一个/:〜,它返回一个排序的参数列表,{从列表中选择一个项目,#返回列表中的项目数, - :half,&lt;。,floor ...和我开始认为它可能是中位数, - 列表中项目数量的一半向下舍入,但#是如何得到它的论点?我看着@标志 - 并意识到那里有三个动词 - 所以这是一个分叉。列表在右边进行排序,然后在左边,fork将列表输入到#以获取参数的数量,然后我们知道它占了一半的底线。所以现在我们有了执行顺序:
排序,并将输出作为右参数传递给中间动词。
占据列表中元素数量的一半,这将成为中间动词的左参数。
做中间动词。
这是我的方法。我同意有时这些短语有太多奇怪的东西,你需要查找它们,但我总是在J instant命令行中找出这些东西。