J語言
来自维基百科,自由的百科全书
J語言,是一種陣列編程語言,由肯尼斯·艾佛森和許國華於1990年代初發明。J語言是APL語言的一種方言[5][6],延續了APL鮮明的簡潔性,它在數學和統計學程式設計上十分高效,特別是在需要進行矩陣運算的場合。
J語言最初起步於肯尼斯·艾佛森在1987年發表的《APL字典》[7],它實現了其中至關重要的秩的概念[8]。J語言提供隱式定義機制包括秩、勾點[9]、叉子[10]和多種函數複合[11],並介入了作為頭等對象的動名詞,用以建立控制結構[12],它常被作為隱式編程的典範之一[13]。
簡介
Ken Iverson(右)和Roger Hui在1996年的相片[14]
J語言的運算子,承襲APL傳統,沒有優先級並且最右先行,2 * 3 + 4
按照2 * (3 + 4)
來運算。以歷史上APL使用的典型符號為例,符號/
被用來指示摺疊函數foldr1
,所以+/1 2 3
等價於1 + (2 + 3)
;在APL中,除法被表示為數學除號÷
,它將減號和冒號一起重複列印在EBCDIC和ASCII二者的紙質文字終端上;J語言使用%
表示除法,是對除號的一種近似或提示。
為了避免APL使用特殊的字元而遇到的問題,J語言只需基本的ASCII字元集,但使用點號.
和冒號:
作為「屈折」[15]。點號和冒號除了前導着空白字元的情況之外,都與緊前字元形成類似雙字元組的短字。多數「基礎」或「原始」的J單字,都充當數學符號,通過點號或冒號來擴充這些可用基本字元的含義。在其他語言中經常是成對的很多字元,比如[] {} "" `` <>
,在J語言中被當作單獨的字,或者在有屈折的時候,作為多字元字的單字元字根。
J語言不再支援從1968年的APL\360就有的[;]
形式的方括號索引,轉而支援叫做「來自」(from)的索引機制[16],它起源自Kenneth E. Iverson於1978年在《算子和函數》中提出的,依據基數解碼定義[17],並用符號⌷
表示的索引[18]。
J語言承襲IBM APL\360採用了平坦陣列模型[19],不支援由NARS(巢狀陣列研究系統)於1981年介入[20],並被IBM APL2所採納的巢狀陣列模型[21];J語言增加了Kenneth E. Iverson於1978年在《算子和函數》中提出的盒裝資料類型[22],它由SHARP APL於1981年介入,並於1983年在I. P. Sharp協會研究報告《理性化APL》中,列入與APL2相比較的「限定子集」(RS)而着重強調[23]。
J語言支援AVX2指令集進行SIMD運算[24]。為了包裝用物件導向程式設計語言開發的API和框架,J語言提供了層級命名空間機制[25],這裏所有名字都存在於特定語境(locale)中[26],可以避免軟件套件之間的名字衝突,並能有效的用作類別為基的物件導向程式設計的框架[27]。
J語言直譯器預設裝載標準庫[28]。通過包管理器[29],還可以安裝各種外掛程式[30],如果是在管理員權限下安裝的J語言直譯器,則安裝外掛程式也需要同樣的管理員權限。J語言擁有常規除錯機制,還有叫做Dissect的可視除錯器[31]。除了科學計算和統計分析,它還被用於關聯式資料庫管理系統如Jd[32]、極限編程[33]和網絡效能分析[34]。
2011年3月,J語言採用了GNU通用公共許可證版本3,從而成為自由和開源軟件[35],人們還可以在Jsoftware的商業許可證下利用原始碼[36]。
文件與詞類
J語言的文件包括在官網的NuVoc中[37],在其中將主要的字羅列為「J原語」,並使用顏色標示出它們分別的詞類[38]。早期的文件還有入門和字典。在J語言中的字,被辨識為名詞[39]、動詞[40]、定語[41](副詞和連詞)、系詞、標點、控制字。一個程式或常式,如果接受數據作為輸入並產生數據作為輸出,則被稱為「動詞」,與之相對,數據參數被稱為「名詞」。
J術語 | APL術語 |
---|---|
名詞 | 陣列 |
動詞 | 函數 |
副詞,連詞 | 算子 |
字母 | 字元集 |
單詞構成 | 詞法分析(lexing) |
標點 | 控制結構,括號界定等 |
句子 | 表達式 |
字典 | 參考手冊 |
雋語(epigram) | 單行代碼(one-liner) |
動詞有兩種形式:只有右側一個參數的一元(monad)形式,和有左右兩側參數的二元(dyad)形式,例如在-1
中減號是一元動詞,而在3-2
中減號是二元動詞。J語言預定義了很豐富的動詞,它們都自動的作用於多種資料類型之上。用戶定義的程式可以自行命名,並用在任何允許使用原始動詞的地方。無論原始動詞還是衍生動詞,它們的一元定義與二元定義,在很大程度上是獨立的。
起步範例
J語言可以寫出非常精簡的程式,特別是存在重度的對符號的函數多載,以至於一些編程者將它稱為難以閱讀的唯寫語言。在電腦的終端上執行ijconsole
,即可進入J語言的REPL直譯器介面。
J語言的「Hello, World!」程式:
'Hello, world!'
Hello, world!
這個Hello World的實現反映了J語言的傳統用法,就是把程式錄入到J直譯器對談中,顯示出表達式結果。還可以準備J指令碼來作為獨立程式來執行,比如在Linux系統上,可以編輯如下內容的一個文字檔案,並命名為比如test01.ijs
:
#!/usr/bin/ijconsole
echo 'Hello, world!'
exit ''
注意第一行的#!
必須頂頭,這裏的echo
和exit
,是與Unix shell中同名命令功能類似的動詞。然後在終端介面中執行這個檔案:
$ ijconsole test01.ijs
Hello, world!
$ chmod +x test01.ijs # 另一种执行方式,授予这个文件可执行权限
$ ./test01.ijs
Hello, world!
在J語言中函數一般稱為動詞,例如定義一個叫做avg
的動詞,計算一序列數的平均:
avg=: +/ % #
avg 1 2 3 4
2.5
一元動詞#
「計數」(tally),總計陣列中專案的總個數。動詞+
「加」(plus)和副詞/
「插入」(insert),衍生出的動詞+/
,合計這個陣列的專案的總和。二元動詞%
「除」(divide)將這個總和除以這個總個數。而用戶定義的動詞avg
,用到了由連串(strand)的三個動詞(+/
、%
和 #
)構成的一個「叉子」(fork)。叉子(f g h) y
↔(f y) g (h y)
,這裏的f
、g
和h
指示動詞,而y
指示一個名詞。
使用avg
的一些例子:
]a=: ?. 20 $100 NB. 产生100以内20个随机整数的一个向量
94 56 8 6 85 48 66 96 76 59 33 72 63 1 89 52 17 20 9 65
avg a
50.75
4 avg\ a NB. 周期大小为4的移动平均
41 38.75 36.75 51.25 73.75 71.5 74.25 66 60 56.75 42.25 56.25 51.25 39.75 44.5 24.5 27.75
]b=: ?. 4 5 $50 NB. 产生50以内20个随机整数的一个矩阵
44 6 8 6 35
48 16 46 26 9
33 22 13 1 39
2 17 20 9 15
avg b
31.75 15.25 21.75 10.5 24.5
avg"1 b NB. 应用avg于m的每个秩为1的子阵列
19.8 29 21.6 12.6
一元副詞/
「插入」(insert),接受位於它左側的一個運算元,並產生將這個動詞應用於其參數的每個專案之間的一個動詞。就是說,+/
是一個動詞,定義為應用+
於給它的參數的各個專案之間。計算移動平均用到的二元副詞\
「中綴」(infix),將作為數據參數的列表劃分成一系列的指定大小的連續專案的子列表,將所修飾動詞應用於其上,並將這些結果形成一個列表。
一元動詞]
「相同」(same),恆等於給它的單一右參數,常像這樣用來在賦值之後顯示變量的內容。一元動詞?.
「擲骰/固定種子」(roll/fixed seed),不同於一元動詞?
「擲骰」(roll),在生成數據參數專案所指定大小範圍內的亂數之時,採用固定的種子。這裏確定對矩陣按行還是按列進行平均,用到了連詞"
「秩」(rank),它在後面的定語章節和單獨條目中論述。
二元動詞i.
「出現索引」(index of),和二元動詞i:
「最後出現索引」(index of last),在任何大小的陣列內尋找匹配者,並返回它的位置索引,如果未找到匹配者,則返回這個陣列的大小。例如:
a=: 3 1 4 1 5 9
a i. 1 2 NB. 找到1和2的第一次出现的索引
1 6
a i: 1 2 NB. 找到1和2的最后一次出现的索引
3 6
在J語言中,排序可以按APL傳統的兩步驟方式[42],使用一元動詞/:
「升序索引」(grade up)或\:
「降序索引」(grade down),和用二元副詞~
「被動」修飾的二元動詞{
「出自」(from),二者連串(strand)形成的一個「勾點」來完成。一元勾點(f g) y
↔y f (g y)
;副詞~
「反身·被動」,其一元定義為f~ y
↔y f y
,二元定義為x f~ y
↔y f x
。J語言還提供專用的二元動詞/:
「上升排序」(sort up)或\:
「下降排序」(sort down)。下面是用例:
a=: 2 0 4 7 15 9 8 0 4 9 18 8 1 18
/: a NB. 产生参数阵列的升序索引
1 7 12 0 2 8 3 6 11 5 9 4 10 13
({~ /:) a NB. 从参数阵列中按升序索引选取出各个项目
0 0 1 2 4 4 7 8 8 9 9 15 18 18
/:~ a
0 0 1 2 4 4 7 8 8 9 9 15 18 18
(a - 10) /: a
_10 _10 _9 _8 _6 _6 _3 _2 _2 _1 _1 5 8 8
load 'pacman' NB. 加载包管理器
'install' jpkg 'tables/csv' NB. 安装CSV文件插件
'showinstalled' jpkg '' NB. 查看已经安装插件
一個CSV檔案簡單用例:
load 'tables/csv' NB. 加载CSV插件
a=: i. 2 3
a writecsv jpath '~/test01.csv' NB. 将一个阵列写入一个CSV文件
12
]b=: readcsv jpath '~/test01.csv' NB. 从一个CSV文件读入一个盒子阵列
┌─┬─┬─┐
│0│1│2│
├─┼─┼─┤
│3│4│5│
└─┴─┴─┘
]c=: makenum b NB. 尽可能的将盒子阵列转换成数值阵列
0 1 2
3 4 5
下面演示使用J語言編寫在管道中的過濾器,例如,在具有隱式編程機制Unix管道的Linux系統中,建立如下內容的文字檔案,並命名為比如filter01.ijs
:
#!/usr/bin/ijconsole
load 'tables/csv'
stdout makecsv 10 + makenum fixcsv stdin ''
exit ''
然後在終端介面中執行如下命令列:
$ cat test01.csv | ijconsole filter01.ijs
10,11,12
13,14,15
資料類型
J語言支援三種簡單類型:
- 數值
- 文字(字元)
- 盒裝
其中數值有很多變種。J語言提供的唯一搜集(collection)類型,是任意維度的陣列。多數演算法可以使用這些陣列來簡潔的表達。
J語言的數值類型之一是「位」。位有兩個值:0
和1
。位還可以形成列表,例如1 0 1 0 1 1 0 0
,是8個位的列表。在語法上,J剖析器將位當作一個字。空格字元被辨識為字形成字元,它處在屬於其他數值字的字元之間。
J語言支援任意長度的列表。J語言進一步的在這些位列表之上,支援所有常見二元運算,比如動詞*.
「與」(and)、+.
「或」(or)、-.
「非」(not)、|.
「反轉·旋轉」(reverse·rotate)、|.!.f
「移位」(shift)等。J語言還支援位的二維、三維等陣列。上面的運算同樣執行在這些陣列之上。
其他數值類型包括整數(比如3、42)、浮點數(3.14、8.8e22)、複數(0j1、2.5j3e88)、擴充精度整數(12345678901234567890x)和(擴充精度)有理分數(1r2、3r4)。同位一樣,它們可以形成列表或任意維度的陣列。同位的情況一樣,運算可以在一個陣列的所有數值之上。下面例子展示π的前50位,超出了IEEE 754雙精度浮點數的53位二進制尾數能精確表示的最大範圍,這就要用到J語言的擴充精度整數:
0j15 ": o. 1 NB. π在双精度浮点数下精确值的位数
3.141592653589793
<.@o. 10x ^50 NB. π乘以扩展精度10的50次幂
314159265358979323846264338327950288419716939937510
這裏採用一元動詞o.
「π乘以」(pi times),和一元動詞<.
「下取整」(floor)二者的複合,得到預期的結果[44]。位的列表可以使用一元動詞#.
「基數2」(base 2)解碼成整數[17]。整數可以使用一元動詞#:
「反基數2」(antibase 2)編碼為位的列表。
J語言還支援文字即字元類型。文字包圍在撇號'
之間,比如'a'
或'b'
。文字的列表,通過將多個字元用撇號包圍起來的常規字串約定來表示,比如'abcdefg'
。在字串內的''
表示'
字元本身。單個的文字,典型的是8
位寬即單位元組的ASCII字元,此外J語言還支援Unicode文字。
不支援在文字上的數值和布林運算,但支援面向搜集的運算,比如旋轉等。使用動詞".
「執行·數值」(do·numbers),將位元組陣列轉換成數值;使用動詞":
「預設格式·格式」(default format·format),將數值轉換成位元組陣列。
盒裝類型的值是0維純量[22],而不管所包含的是怎樣的數據結構。使用一元動詞<
「盒裝」(box),將數據放置入盒子中;使用一元動詞>
「打開」(open),打開盒子中取出其中數據。還可以通過二元動詞;
「連結」(link)建立盒子的列表,通過一元動詞;
「拆除」(raze)移除一層盒子的列表。盒子內可以裝入其他盒子,還可以通過二元動詞$
「重製形狀」(reshape)和二元動詞#
「計件複製」(copy)等操作盒子及其列表。
J語言的陣列,具有同質(homogeneous)的專案類型,例如列表1 2 3
是整數的列表,儘管1
還可以是一個位。這種類型問題,在極大程度上對於編程者是透明的。只有特定的特殊運算,會顯露出在類型上的不同。例如列表1.0 0.0 1.0 0.0
,對大多數運算,將被當作是完全同於列表1 0 1 0
。
J語言支援數值稀疏陣列,通過它們的下標儲存非零數值。這在非零數值相對很少的情況下,是有效率的機制。
簡要詞彙表
下面的表格簡要列出了常用詞彙。如果含義中用了間隔號( · )分隔,通常前者是只有一個右側參數的一元含義,後者是左右兩側都有參數的二元含義。列出的對應APL符號,是Dyalog等現代APL所採用的符號。
定語
定義
索引
範例
參見
參照
外部連結
Wikiwand - on
Seamless Wikipedia browsing. On steroids.