J语言
J编程语言,是肯尼斯·艾佛森和許國華於1990年代初發明的一种阵列编程语言[4][5],是APL語言(亦是由图灵奖获得者艾佛森所創)的繼承者。
| 阵列、函数式、函数级、隐式 | |
| 設計者 | Kenneth E. Iverson、許國華 |
| 實作者 | JSoftware |
| 1990年 | |
| 穩定版本 | J901
(2019年12月15日[1]
) |
| 型態系統 | 类型系统 |
| 作業系統 | 跨平台: Windows, Linux, macOS |
| 許可證 | GPLv3 |
| 網站 | www |
| 主要實作產品 | |
| J | |
| 啟發語言 | |
| APL | |
| 影響語言 | |
| NumPy[2],SuperCollider[3] | |
简介
作為一個陣列編程語言,J非常簡潔和強大,在數學和统计学程式設計上十分有效,特別是需要进行矩陣运算的时候。它还被用于极限编程[6]和网络性能分析[7]。
為了避免APL使用特殊的字符而遇到的問題,J只需基本的ASCII字符集,但使用点号.和冒号:作为“屈折”[8]。在分析J的时候,点号.和冒号:只在前导着空白字符时是单独的字;在其他情况下,点号和冒号是字形成字符,与紧前字符形成类似双字符组的短字,多数这种“基础”(或“原语”)的J字都充当数学符号,具有用点号或冒号从能获得的基本字符扩展来的含义。还有,很多字符在其他语言中经常是成对的(比如[] {} "" `` <>),在J中被当作单独的字,或者在有屈折的时候,作为多字符字的单字符字根。
如同图灵奖获得者約翰·巴科斯的FP和FL程式語言,J透過它隱式編程的特色,支援函數級編程。不同于支持面向对象编程的多数语言,J灵活的层次名字空间体制(这里所有名字都存在于特定区域中),可以有效的用作基于类和基于实例的面向对象编程二者的框架。
自从2011年三月,J成为了自由和开源软件,采用了GNU通用公共许可证版本3(GPLv3)[9][10][11]。人们还可以在商业许可证下利用源代码[12]。
起步示例
J允许无点风格和函数复合。因此,它的程序可以非常精简,一些编程者将它称为难以阅读的只写语言。
J的“Hello, World!”程序:
'Hello, world!'
这个hello world的实现反映了J的传统用法,就是把程序录入到J解释器会话中,显示出表达式结果。还可以准备J脚本来作为独立程序来执行。下面是在Linux系统的上的样子:
#!/usr/bin/ijconsole
echo 'Hello, world!'
exit ''
J的算符没有优先级并且最右先行,2 * 3 + 4的结果是14。历史上,APL使用/来指示fold,所以+/1 2 3等价于1 + 2 + 3。在APL中,除法被表示为数学除号 (÷),它将减号和冒号一起重复打印(在EBCDIC和ASCII二者的纸质文本终端上)。因为ASCII一般不支持设备无关方式的重复打印,并且本身不包括除号,J使用%表示除法,作为一种可视的近似或暗示。(这展示了J记号的某些助忆符特征,和使用ASCII带来的一些困扰。)
定义一个J函数叫做avg,计算一列数的平均:
avg=: +/ % #
下面是这个函数的测试执行:
avg 1 2 3 4
2.5
#计数在阵列中项目的数目。+/合计这个阵列的项目。%将这个合计除以这个总数。上述的avg使用一连串的三个动词(+/、%和 #)来定义,术语叫“叉子”(fork)。特别是(V0 V1 V2) Ny同于(V0(Ny)) V1 (V2(Ny)),这展示了J的一些能力。(这里的V0、V1和V2指示动词而Ny指示一个名词。)
使用avg的一些例子:
v=: ?. 20 $100NB. 一个随机向量v46 55 79 52 54 39 60 57 60 94 46 78 13 18 51 92 78 60 90 62avg v59.24 avg\ vNB. 周期大小为4的移动平均 58 60 56 51.25 52.5 54 67.75 64.25 69.5 57.75 38.75 40 43.5 59.75 70.25 80 72.5
m=: ?. 4 5 $50NB. 一个随机矩阵m46 5 29 2 4 39 10 7 10 44 46 28 13 18 1 42 28 10 40 12avg m43.25 17.75 14.75 17.5 15.25avg"1 mNB. 应用avg于m的每个阶1的子阵列 17.2 22 21.2 26.4
动词i.和i:在任何大小的阵列内查找匹配者:
3 1 4 1 5 9 i. 3 1NB. 找到3和1的第一次出现的索引 0 13 1 4 1 5 9 i: 3 1NB. 找到3和1的最后一次出现的索引 0 3
除了使用标准库 页面存档备份,存于之外,还可以用包管理器安装插件 页面存档备份,存于,例如内存映射文件插件:
load 'pacman' NB. 加载包管理器
'install' jpkg 'data/jmf' NB. 安装内存映射文件插件
数据类型和结构
J支持三种简单类型:
- 数值
- 文字(字符)
- 盒装
其中数值有很多变种。J的数值类型之一是“位”。有两个位值:0和1。还有,位可以形成列表。例如,1 0 1 0 1 1 0 0是八个位的列表。在语法上,J分析器将位当作一个字。(空格字符被识别为字形成字符,位于在其他数值字的字符之间。)支持任意长度的列表。
进一步的,J支持在这些列表之上的所有常见二元运算,比如“与”、“或”、“亦或”、“旋转”、“移位”、“非”等。例如:
1 0 0 1 0 0 1 0 +. 0 1 0 1 1 0 1 0NB. 或 1 1 0 1 1 0 1 0<nowiki>3 |. 1 0 1 1 0 0 1 1 1 1 1</nowiki>NB. 旋转 1 0 0 1 1 1 1 1 1 0 1
J还支持位的高阶阵列。它们可以被形成二维、三维等阵列。上面的运算同样的运行在这些阵列之上。
其他数值类型包括整数(比如3, 42)、浮点数(3.14, 8.8e22)、复数(0j1, 2.5j3e88)、扩展精度整数(12345678901234567890x)和(扩展精度)有理分数(1r2, 3r4)。同位一样,它们可以形成列表或任意维度的阵列。同位一样,运算可以在一个阵列的所有数之上。下面表达式展示n位的pi,演示了J的扩展精度的能力:
n=: 50NB. 设置n为要求的数字数目<.@o. 10x^nNB. 扩展精度10的n次幂*pi 314159265358979323846264338327950288419716939937510
位的列表可以使用#.动词转化成整数。整数可以使用#:动词转化为位的列表。
J还支持文字(字符)类型。文字包围在引号之间,比如'a'或'b'。文字的列表使用将多个字符放入引号之内的常规约定来支持,比如'abcdefg'。典型的,单独的文字是8-位宽(ASCII),但是J还支持其他文字(Unicode)。不支持在文字上的数值和布尔运算,但支持面向集合的运算(比如旋转)。
最后,有一种盒装数据类型。典型的,数据使用<运算来放置入盒子中(没有左侧参数,如果有左侧参数就是“小于”运算)。这类似于C的&运算(没有左侧参数)。但是,C语言的&的结果拥有引用语义,而J的<结果拥有值的语义。换句话说,<是一个函数并产生一个结果。这个结果是0维度的,不管包含怎样的数据的结构。从J编程者的角度看,<将数据放置到一个盒子中,并允许有效使用盒子的列表(它可以用其他盒子来组装,和/或制作盒子的更多副本)。
J提供的唯一集合(collection)类型是任意维度的阵列。多数算法可以使用这些阵列来简洁的表达。
J的阵列是有同质的类型,例如列表1 2 3是整数的列表,尽管1可以是一个位。在极大程度上,这种的类型问题对于编程者是透明的。只有特定的特殊运算显露出在类型上的不同。例如,列表1.0 0.0 1.0 0.0,对大多数运算,将被当作是完全同于列表1 0 1 0。
J还支持数值稀疏阵列,这里用它们的下标存储非零数值。这在非零数值相对很少的情况下是有效率的机制。
J还支持对象和类[13],但是它们是事物命名方式的人工制品,而非数据类型。实际上,使用盒装文字来提及对象(和类)。J数据有值语义,但是对象和类需要引用语义。
动词和修饰词
一个程序或例程,有时接受数据作为输入并产生数据作为输出,被称为“动词”,与之相对,数据参数被称为“名词”。J有一组丰富的预定义的动词,它们都自动的起作用于多种数据类型之上。用户的程序可以命名,并可以用在任何允许使用原语的地方。
秩是J中的决定性概念。它在J中的重要性类似于SQL中的select和C语言中的while的重要性。
J的能力很大程度上来自它的“修饰词”,这个范畴包括“副词”和“连词”:这些符号接受名词和动词作为操作者(operand),并以指定方式应用这些操作者。例如,修饰词/接受位于它左侧的一个操作者,并产生应用这个动词在它的参数的每个项目之间的一个动词。就是说,+/是一个动词,定义为应用+在你的参数的项目之间。
在J中孤立的动词序列叫做“列车”(train),J支持叫作“叉子”(fork)和“钩子”(hook)的不可见连词,它们规定了如何将参数或应用成员动词于参数的结果提供给成员动词来应用的规则。
J有大约两打各种修饰词。它们都可以应用到任何动词,甚至是用户写的动词,用户可以写自己的修饰词。修饰词都是各有各的能力的:
^:动词幂,固定幂和动态幂能进行条件执行,相当于if块结构,动态幂还能进行重复执行,相当于do-while块结构;`连结(动名词)和@.议程(agenda),一起进行选择执行,相当于if-else等块结构;\中缀和;.剪切等,分别进行参数的规则或不规则的子集的执行;@:(at)、@(atop)、&:(appose)、&(compose),是四种复合。
利用上各种修饰词能产生实际编程所需要的运算操作的无限多种变体。
| 连词 | 一元 | 二元 | 秩 页面存档备份,存于 |
|---|---|---|---|
| fork | (f g h) y = (f y) g (h y) | x (f g h) y = (x f y) g (x h y) | _ _ _ |
| hook | (f g) y = y f (g y) | x (f g) y = x f (g y) | _ _ _ |
@: | (f @: g) y = f (g y) | x (f @: g) y = f (x g y) | _ _ _ |
@ | (f @ g) y = f"g (g y) | x (f @ g) y = x ((f @: g)"LG RG) y | MG LG RG |
&: | (f &: g) y = f (g y) | x (f &: g) y = (g x) f (g y) | _ _ _ |
& | (f & g) y = f"g (g y) | x (f & g) y = (g x) f"MG (g y) | MG MG MG |
在上表中,MG =: 0{(g b.)0,LG =: 1{(g b.)0,RG =: 2{(g b.)0,在上四种复合的实际运作机制及其异同详见图示 页面存档备份,存于。下面是四种复合及结果值扩充的示意例子:
] a <nowiki>=</nowiki>: >:i. 2 31 2 3
4 5 6] b <nowiki>=</nowiki>: 0.1*>:i. 20.1 0.2a (< @: +) b┌───────────┐
│1.1 2.1 3.1│
│4.2 5.2 6.2│
└───────────┘a (< @ +) b┌───┬───┬───┐
│1.1│2.1│3.1│
├───┼───┼───┤
│4.2│5.2│6.2│
└───┴───┴───┘a (; &: +:) b┌───────┬───────┐
│2 4 6│0.2 0.4│
│8 10 12│ │
└───────┴───────┘a (; & +:) b┌──┬───┐
│2 │0.2│
├──┼───┤
│4 │0.2│
├──┼───┤
│6 │0.2│
└──┴───┘
┌──┬───┐
│8 │0.4│
├──┼───┤
│10│0.4│
├──┼───┤
│12│0.4│
└──┴───┘a , b1 2 3
4 5 6
0.1 0.2 0a <nowiki>=</nowiki>: >:i. 1 2 3a , b1 2 3
4 5 6
0.1 0.2 0
0 0 0
文档
J的文档包括于NuVoc 页面存档备份,存于中,在J中的字被识别为名词页面存档备份,存于、动词页面存档备份,存于、修饰词 页面存档备份,存于(副词和连词)、系词、标点符号、控制字。主要的字列于“J原语”中,其中使用颜色标示出它们分别的词类页面存档备份,存于。早期的文档还有入门 页面存档备份,存于和字典 页面存档备份,存于。注意动词有两种形式:一元(参数只在右侧)和二元(参数在左右两侧)。例如,在-1中横杠是一元动词,而在3-2中横杠是二元动词。一元定义很大程度上独立于二元定义,不管这个动词是原语动词还是派生动词。
最基本词汇
下表最基本词汇 页面存档备份,存于含义中如果用了间隔号( · )分隔,通常前面是一元含义(只有一个右侧参数),后者是二元含义(左右两侧都有参数)。
| 词汇 | 含义 | 例子 | |
|---|---|---|---|
| 基本 | =. | 是为(局部赋值) | loc=. 1 2 |
=: | 是为(全局赋值) | GLO=: 'foo' | |
_ | 负号 / 无穷 | _3 = -3 | |
NB. | 注释 | NB. negative vs. negate | |
'字符串' | 字符串 | '' NB. Empty vector'Hello, World!' | |
| 阵列 | $ | 形状 · 制成形状 | 2 2 4 $ 1 2 11 22 |
# | 计数 · 计件复制 | 1 2 3 # 1 2 3 | |
, | 平展 · 附加 | , 2 2$99 | |
; | 拆开 · 链接 | 23 ; 'skidoo' | |
{. | 选用 | 3 {. 'foot' | |
}. | 弃用 | 2 }. 1 2 3 4 | |
/ | 插入 · 张开表格 | + / 1 10 100 | |
i. | 整数序列 · 出现索引 | i. 10'foo' i. 'o' | |
| 数学 | + | 共轭复数 · 加法 | 2 + 3 30 |
* | 符号函数 · 乘法 | 3 30 * 2 | |
- | 相反数 · 减法 | 1 10 - 5 6 | |
% | 倒数 · 除法 | 2 3 5 % 3 4 6 | |
^ | 指数 · 幂 | 2 ^ i.17 | |
^. | 自然对数 · 对数 | 2 10 ^. 4 100^. 2.71828 | |
<. | 下取整 · 取最小 | 2 3 4 <. 99 1 2 | |
>. | 上取整 · 取最大 | >. 1.1 0.5 1.9 | |
控制结构
J提供了类似其他过程语言的控制结构,可用在显式定义之中。每个范畴内的代表性控制字包括:
| 范畴 | 控制结构 |
|---|---|
| 断言触发 | assert. |
| 终止循环 | break. |
| 终止本次迭代 | continue. |
| 逐项执行 | for. T do. B end. |
| 跳转到标号 | goto_label. label_lbl. |
| 条件执行 | if. T do. B else. B1 end. |
| 返结果退出 | return. |
| 情况执行 | select. T case. T0 do. B0 end. |
| 抛出异常 | throw. |
| 尝试执行捕获异常 | try. B catch. B1 end. |
| 条件循环 | while. T do. B end. |
例子程序
快速排序
sel=: adverb def 'u # ['
quicksort=: verb define
if. 1 >: #y do. y
else.
(quicksort y <sel e),(y =sel e),quicksort y >sel e=.y{~?#y
end.
)
下面是展示隐式编程的快速排序的实现。它涉及到将函数复合在一起而不显式的引用任何变量。
quicksort=: (($:@(<#[), (=#[), $:@(>#[)) ({~ ?@#)) ^: (1<#)
在J中排序通常使用内建原语动词/:升序或\:降序与{选取来一起完成。上面的用户定义的排序比如快速排序,典型的只用作演示。
用例:
quicksort 15 2 9 10 4 0 13 13 18 70 2 4 7 9 10 13 13 15 18(/: { ]) 15 2 9 10 4 0 13 13 18 70 2 4 7 9 10 13 13 15 18
斐波那契数列
下面是演示使用自引用动词$:来递归的计算斐波那契数列的例子:
fibonacci=:1:`($:@-&2+$:@<:)@.(>&2)
注意这里的1:是常量动词,这个递归还可以通过用名字引用动词来完成,当然这只在动词有命名的时候是可行的:
fibonacci=:1:`(fibonacci@-&2+fibonacci@<:)@.(>&2)
用例:
fibonacci"0 }.i.10
1 1 2 3 5 8 13 21 34
内存映射文件
将J中的变量映射到文件系统中的持久文件:
load 'data/jmf' NB. 加载插件
] V =: 2 2 $ 1 2 3 4 NB. 测试用阵列数值
S =: 64000 NB. 文件大小(字节)
F =: '~/persis.jmf' NB. 文件路径及名字
createjmf_jmf_ F;S NB. 建立并打开持久文件
map_jmf_ 'P'; F NB. 映射变量至持久文件
P =: V NB. 将测试内容赋值到P
unmap_jmf_ 'P' NB. 解除映射并关闭文件
map_jmf_ 'Q' ; F NB. 再次建立映射
] Q NB. 查看持久文件保存内容
unmap_jmf_ 'Q' NB. 再次解除映射
调试

J拥有常规设施可以停止在动词内错误或特定位置上。它还有一个唯一的可视调试器,叫做Dissect 页面存档备份,存于,给出一个单一的J句子执行的2-D交互显示。因为J的一个单一句子在低层语言中是作为一个完整的子例程进行计算的,这个可视显示非常有用。
参见
引用
- . [2020-04-18]. (原始内容存档于2020-05-31).
- . [2020-04-18]. (原始内容存档于2020-05-30).
- . [2020-04-18]. (原始内容存档于2020-12-11).
- A Personal View of APL, 1991 essay by K.E. Iverson (archived link)
- Overview of J history 页面存档备份,存于 by Roger Hui (19 March 2002)
- Bussell, Brian; Taylor, Stephen, , , Oulu, Finland: Springer: 21–31, 2006, ISBN 978-3-540-35094-1
- Holt, Alan, , Springer, 2007, ISBN 978-1-84628-822-7
- . [2020-05-18]. (原始内容存档于2016-03-07).
- . [2020-05-18]. (原始内容存档于2021-01-26).
- Eric Iverson. . J programming mailing list. 1 March 2011 [2020-05-18]. (原始内容存档于2016-09-23).
- GitHub上的openj
- . [2020-05-18]. (原始内容存档于2021-01-26).
- . [2020-05-18]. (原始内容存档于2020-06-25).
外部連結
- JSoftware页面存档备份,存于,J的官方網站
- GitHub上的Jsoftware頁面 – Repository
- Learning J 页面存档备份,存于 – An Introduction to the J Programming Language by Roger Stokes
- J for C Programmers 页面存档备份,存于 by Henry Rich
- J for the APL Programmer 页面存档备份,存于 by Chris Burke and Roger Hui
- An Implementation of J 页面存档备份,存于 by Roger K.W. Hui
- APL to J Phrasebook 页面存档备份,存于
- 郭平欣教授之J語言初步 页面存档备份,存于
- 郭平欣教授之J字典 页面存档备份,存于