編程範型 | 陣列、隱式、函數級、函數式 |
---|---|
設計者 | Kenneth E. Iverson、許國華 |
實作者 | JSoftware |
面市時間 | 1990年 |
穩定版本 | J903
(2021年12月16日[1]
) |
型態系統 | 類型系統 |
作業系統 | 跨平台: Windows, Linux, macOS |
許可證 | GPLv3 |
網站 | www |
主要實作產品 | |
J | |
受啟發於 | |
APL | |
施影響於 | |
NumPy[2],SuperCollider[3] |
J編程語言,是一種陣列編程語言,由肯尼斯·艾佛森和許國華於1990年代初發明,是APL語言的繼承者[4][5]。
簡介
J透過它隱式編程的特色,同約翰·巴科斯的FP和FL程式語言一樣,支援函數級編程。不同於支持面向對象編程的多數語言,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中,除法被表示為數學除號 (÷
),它將減號和冒號一起重複打印(在EBCDIC和ASCII二者的紙質文本終端上)。因為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 62avg v|j
59.24 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 12avg m|j
43.25 17.75 14.75 17.5 15.25avg"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 13 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的數值類型之一是「位」。有兩個位值: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 0|j
NB. 或 1 1 0 1 1 0 1 03 |. 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中的select
和C語言中的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.)0
,LG =: 1{(g b.)0
,RG =: 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.2a (< @: +) 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 0a =: >: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.
|
例子程序
快速排序
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. 再次解除映射
調試
J擁有常規設施可以停止在動詞內錯誤或特定位置上。它還有一個唯一的可視調試器,叫做Dissect[31],給出一個單一的J句子執行的2-D交互顯示。因為J的一個單一句子在低層語言中是作為一個完整的子例程進行計算的,這個可視顯示非常有用。
參見
引用
- ↑ J903 release 16 December 2021.
- ↑ Wes McKinney at 2012 meeting Python for Data Analysis. [2020-04-18].
- ↑ SuperCollider documentation, Adverbs for Binary Operators. [2020-04-18].
- ↑ A Personal View of APL, 1991 essay by K.E. Iverson (archived link)
- ↑ Overview of J history by Roger Hui (19 March 2002)
- ↑ J NuVoc Words. [2020-05-18].
- ↑ AVX
- ↑ 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
- ↑ Holt, Alan, Network Performance Analysis: Using the J Programming Language, Springer, 2007, ISBN 978-1-84628-822-7
- ↑ Jsoftware's source download page. [2020-05-18].
- ↑ Eric Iverson. J Source GPL. J programming mailing list. 1 March 2011 [2020-05-18].
- ↑ GitHub上的openj
- ↑ Jsoftware's sourcing policy. [2020-05-18].
- ↑ 標準庫
- ↑ 包管理器
- ↑ 插件
- ↑ Chapter 25: Object-Oriented Programming. [2020-05-18].
- ↑ 內存映射文件
- ↑ 秩
- ↑ 圖示
- ↑ NuVoc
- ↑ 名詞
- ↑ 動詞
- ↑ 修飾詞
- ↑ 詞類
- ↑ 入門
- ↑ 字典
- ↑ 最基本詞彙
- ↑ 控制結構
- ↑ J字典
- ↑ Dissect
外部連結
- 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字典