J语言

本页使用了标题或全文手工转换,现处于中国大陆简体模式
求闻百科,共笔求闻
J
编程范型阵列隐式函数级函数式
设计者Kenneth E. Iverson许国华
实现者JSoftware
发行时间1990年,​34年前​(1990
稳定版本
J903
(2021年12月16日,​2年前​(2021-12-16[1]
类型系统类型系统
操作系统跨平台: Windows, Linux, macOS
许可证GPLv3
网站www.jsoftware.com
主要实现产品
J
受启发于
APL
施影响于
NumPy[2]SuperCollider[3]

J编程语言,是一种阵列编程语言,由肯尼斯·艾佛森许国华于1990年代初发明,是APL语言的继承者[4][5]

简介

J透过它隐式编程的特色,同约翰·巴科斯FPFL编程语言一样,支持函数级编程。不同于支持面向对象编程的多数语言,J灵活的层次名字空间机制(这里所有名字都存在于特定区域中),可以有效的用作基于类基于原型的面向对象编程二者的框架。

为了避免APL使用特殊的字符而遇到的问题,J只需基本的ASCII字符集,但使用点号.和冒号:作为“屈折[6]。在分析J的时候,点号.和冒号:只在前导着空白字符时是单独的字;在其他情况下,点号和冒号是字形成字符,与紧前字符形成类似双字符组的短字,多数这种“基础”(或“原语”)的J字都充当数学符号,具有用点号或冒号从能获得的基本字符扩展来的含义。还有,很多字符在其他语言中经常是成对的(比如[] {} "" `` <>),在J中被当作单独的字,或者在有屈折的时候,作为多字符字的单字符字根

J支持AVX指令集进行SIMD运算[7]。J作为一个数组编程语言,非常简洁和强大,在数学统计学程序设计上十分有效,特别是需要进行矩阵运算的时候。它还被用于极限编程[8]网络性能分析[9]

自从2011年3月,J成为了自由和开源软件,采用了GNU通用公共许可证版本3(GPLv3)[10][11][12]。人们还可以在商业许可证下利用源代码[13]

起步示例

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中,除法被表示为数学除号 (÷),它将减号和冒号一起重复打印(在EBCDICASCII二者的纸质文本终端上)。因为ASCII一般不支持设备无关方式的重复打印,并且本身不包括除号,J使用%表示除法,作为一种可视的近似或暗示。(这展示了J记号的某些助忆符特征,和使用ASCII带来的一些困扰。)

定义一个J函数叫做avg,计算一列数的平均:

  avg=: +/ % #|j

下面是这个函数的测试执行:

  avg 1 2 3 4|j
2.5

#计数在阵列中项目的数目。+/合计这个阵列的项目。%将这个合计除以这个总数。上述的avg使用一连串的三个动词(+/%#)来定义,术语叫“叉子”(fork)。特别是(V0 V1 V2) Ny同于(V0(Ny)) V1 (V2(Ny)),这展示了J的一些能力。(这里的V0、V1和V2指示动词而Ny指示一个名词。)

使用avg的一些例子:

  v=: ?. 20 $100|j     NB. 一个随机向量
  v
46 55 79 52 54 39 60 57 60 94 46 78 13 18 51 92 78 60 90 62
  avg v|j
59.2
  4 avg\ v|j           NB. 周期大小为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 $50|j     NB. 一个随机矩阵
  m
46  5 29  2  4
39 10  7 10 44
46 28 13 18  1
42 28 10 40 12
  avg m|j
43.25 17.75 14.75 17.5 15.25
  avg"1 m|j            NB. 应用avg于m的每个阶1的子阵列
17.2 22 21.2 26.4

动词i.i:在任何大小的阵列内查找匹配者:

  3 1 4 1 5 9 i. 3 1|j  NB. 找到3和1的第一次出现的索引
0 1
  3 1 4 1 5 9 i: 3 1|j  NB. 找到3和1的最后一次出现的索引
0 3

除了使用标准库[14]之外,还可以用包管理器[15]安装插件[16],例如内存映射文件插件:

   load 'pacman'                NB. 加载包管理器
   'install' jpkg 'data/jmf'    NB. 安装内存映射文件插件

数据类型和结构

J支持三种简单类型:

  • 数值
  • 文字(字符)
  • 盒装

其中数值有很多变种。J的数值类型之一是“”。有两个位值:01。还有,位可以形成列表。例如,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 0|j     NB. 或
1 1 0 1 1 0 1 0
  3 |. 1 0 1 1 0 0 1 1 1 1 1|j             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=: 50|j                      NB. 设置n为要求的数字数目
  <.@o. 10x^n|j                 NB. 扩展精度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还支持对象[17],但是它们是事物命名方式的人工制品,而非数据类型。实际上,使用盒装文字来提及对象(和类)。J数据有值语义,但是对象和类需要引用语义。

另一个伪类型,关联于名字而非数值,是内存映射文件[18]

动词和修饰词

一个程序或例程,有时接受数据作为输入并产生数据作为输出,被称为“动词”,与之相对,数据参数被称为“名词”。J有一组丰富的预定义的动词,它们都自动的起作用于多种数据类型之上。用户的程序可以命名,并可以用在任何允许使用原语的地方。

是J中的决定性概念。它在J中的重要性类似于SQL中的selectC语言中的while的重要性。

J的能力很大程度上来自它的“修饰词”,这个范畴包括“副词”和“连词”:这些符号接受名词和动词作为操作者(operand),并以指定方式应用这些操作者。例如,修饰词/接受位于它左侧的一个操作者,并产生应用这个动词在它的参数的每个项目之间的一个动词。就是说,+/是一个动词,定义为应用+在你的参数的项目之间。

在J中孤立的动词序列叫做“列车”(train),J支持叫作“叉子”(fork)和“钩子”(hook)的不可见连词,它们规定了如何将参数或应用成员动词于参数的结果提供给成员动词来应用的规则。

J有大约两打各种修饰词。它们都可以应用到任何动词,甚至是用户写的动词,用户可以写自己的修饰词。修饰词都是各有各的能力的:

  • ^:动词幂,固定幂和动态幂能进行条件执行,相当于if块结构,动态幂还能进行重复执行,相当于do-while块结构;
  • `链接(动名词)和@.议程(agenda),一起进行选择执行,相当于if-else等块结构;
  • \中缀和;.剪切等,分别进行参数的规则或不规则的子集的执行;
  • @:(at)、@(atop)、&:(appose)、&(compose),是四种复合

利用上各种修饰词能产生实际编程所需要的运算操作的无限多种变体。

连词 一元 二元 [19]
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.)0LG =: 1{(g b.)0RG =: 2{(g b.)0,在上四种复合的实际运作机制及其异同详见图示[20]。下面是四种复合及结果值扩充的示意例子:

  ] a =: >:i. 2 3|j
1 2 3
4 5 6
] b =: 0.1*>:i. 2|j 0.1 0.2 a (< @: +) b|j ┌───────────┐
│1.1 2.1 3.1│
│4.2 5.2 6.2│
└───────────┘
a (< @ +) b|j ┌───┬───┬───┐
│1.1│2.1│3.1│
├───┼───┼───┤
│4.2│5.2│6.2│
└───┴───┴───┘
a (; &: +:) b|j ┌───────┬───────┐
│2 4 6│0.2 0.4│
│8 10 12│ │
└───────┴───────┘
a (; & +:) b|j ┌──┬───┐
│2 │0.2│
├──┼───┤
│4 │0.2│
├──┼───┤
│6 │0.2│
└──┴───┘
┌──┬───┐
│8 │0.4│
├──┼───┤
│10│0.4│
├──┼───┤
│12│0.4│
└──┴───┘
a , b|j 1 2 3
4 5 6
0.1 0.2 0
a =: >:i. 1 2 3|j a , b|j 1 2 3
4 5 6

0.1 0.2 0
0 0 0

文档

J的文档包括于NuVoc[21]中,在J中的字被识别为名词[22]、动词[23]、修饰词[24](副词和连词)、系词标点符号控制字。主要的字列于“J原语”中,其中使用颜色标示出它们分别的词类[25]。早期的文档还有入门[26]和字典[27]。注意动词有两种形式:一元(参数只在右侧)和二元(参数在左右两侧)。例如,在-1中横杠是一元动词,而在3-2中横杠是二元动词。一元定义很大程度上独立于二元定义,不管这个动词是原语动词还是派生动词。

最基本词汇

下表最基本词汇[28]含义中如果用了间隔号( · )分隔,通常前面是一元含义(只有一个右侧参数),后者是二元含义(左右两侧都有参数)。

词汇 含义 例子
基本 =. 是为(局部赋值) 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提供了类似其他过程语言的控制结构[29],可用在显式定义之中。每个范畴内的代表性控制字包括:

范畴 控制结构
断言触发 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.

例子程序

快速排序

实现升序快速排序,代码来自J字典[30]

   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 7|j
0 2 4 7 9 10 13 13 15 18
  (/: { ]) 15 2 9 10 4 0 13 13 18 7|j
0 2 4 7 9 10 13 13 15 18

斐波那契数列

下面是演示使用自引用动词$:来递归的计算斐波那契数列的例子:

fibonacci=:1:`($:@-&2+$:@<:)@.(>&2)

注意这里的1:是常量动词,这个递归还可以通过用名字引用动词来完成,当然这只在动词有命名的时候是可行的:

fibonacci=:1:`(fibonacci@-&2+fibonacci@<:)@.(>&2)

用例:

  fibonacci"0 }.i.10|j
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. 再次解除映射

调试

剖析开始于6的考拉兹序列

J拥有常规设施可以停止在动词内错误或特定位置上。它还有一个唯一的可视调试器,叫做Dissect[31],给出一个单一的J句子执行的2-D交互显示。因为J的一个单一句子在低层语言中是作为一个完整的子例程进行计算的,这个可视显示非常有用。

参见

引用

  1. J903 release 16 December 2021. 
  2. Wes McKinney at 2012 meeting Python for Data Analysis. [2020-04-18]. 
  3. SuperCollider documentation, Adverbs for Binary Operators. [2020-04-18]. 
  4. A Personal View of APL, 1991 essay by K.E. Iverson (archived link)
  5. Overview of J history by Roger Hui (19 March 2002)
  6. J NuVoc Words. [2020-05-18]. 
  7. AVX
  8. Bussell, Brian; Taylor, Stephen, Software Development as a Collaborative Writing Project, Extreme programming and agile processes in software engineering, Oulu, Finland: Springer: 21–31, 2006, ISBN 978-3-540-35094-1 
  9. Holt, Alan, Network Performance Analysis: Using the J Programming Language, Springer, 2007, ISBN 978-1-84628-822-7 
  10. Jsoftware's source download page. [2020-05-18]. 
  11. Eric Iverson. J Source GPL. J programming mailing list. 1 March 2011 [2020-05-18]. 
  12. GitHub上的openj
  13. Jsoftware's sourcing policy. [2020-05-18]. 
  14. 标准库
  15. 包管理器
  16. 插件
  17. Chapter 25: Object-Oriented Programming. [2020-05-18]. 
  18. 内存映射文件
  19. 图示
  20. NuVoc
  21. 名词
  22. 动词
  23. 修饰词
  24. 词类
  25. 入门
  26. 字典
  27. 最基本词汇
  28. 控制结构
  29. J字典
  30. Dissect

外部链接