J编程语言

**J** 語言，是一種陣列編程語言，由肯尼斯・艾佛森和許國華於 1990 年代初發明。J 語言是 APL 語言的一種方言，延續了 APL 鮮明的簡潔性，它在數學和統計學程式設計上十分高效，特別是在需要進行矩陣運算的場合。

J 語言最初起步於肯尼斯・艾佛森在 1987 年發表的《APL 字典》，它實現了其中至關重要的秩的概念。J 語言提供隱式定義機制包括秩、勾點、叉子和多種函式複合，並介入了作為頭等物件的動名詞，用以建立控制結構，它常被作為隱式編程的典範之一。

## 簡介

J 語言的運算子，承襲 APL 傳統，沒有優先級並且最右先行，`2 * 3 + 4` 按照 `2 * (3 + 4)` 來運算。以歷史上 APL 使用的典型符號為例，符號 `/` 被用來指示摺疊函式 `foldr1`，所以 `+/1 2 3` 等價於 `1 + (2 + 3)`；在 APL 中，除法被表示為數學除號 `÷`，它將減號和冒號一起重複列印在 EBCDIC 和 ASCII 二者的紙質文字終端上；J 語言使用 `%` 表示除法，是對除號的一種近似或提示。

為了避免 APL 使用特殊的字元而遇到的問題，J 語言只需基本的 ASCII 字元集，但使用點號 `.` 和冒號 `:` 作為「屈折」。點號和冒號除了前導著空白字元的情況之外，都與緊前字元形成類似雙字元組的短字。多數「基礎」或「原始」的 J 單字，都充當數學符號，通過點號或冒號來擴充這些可用基本字元的含義。在其他語言中經常是成對的很多字元，比如 `[] {} "" `` <>`，在 J 語言中被當作單獨的字，或者在有屈折的時候，作為多字元字的單字元字根。

J 語言不再支援從 1968 年的 APL\360 就有的 `[;]` 形式的方括號索引，轉而支援叫做「來自」（from）的索引機制，它起源自 Kenneth E. Iverson 於 1978 年在《算子和函式》中提出的，依據基數解碼定義，並用符號 `⌷` 表示的索引。

J 語言承襲 IBM APL\360 採用了平坦陣列模型，不支援由 NARS（巢狀陣列研究系統）於 1981 年介入，並被 IBM APL2 所採納的巢狀陣列模型；J 語言增加了 Kenneth E. Iverson 於 1978 年在《算子和函式》中提出的盒裝資料類型，它由 SHARP APL 於 1981 年介入，並於 1983 年在 I. P. Sharp 協會研究報告《理性化 APL》中，列入與 APL2 相比較的「限定子集」（RS）而著重強調。

J 語言支援 AVX2 指令集進行 SIMD 運算。為了包裝用物件導向程式設計語言開發的 API 和框架，J 語言提供了層級命名空間機制，這裡所有名字都存在於特定語境（locale）中，可以避免軟體套件之間的名字衝突，並能有效的用作類別為基的物件導向程式設計的框架。

J 語言直譯器預設裝載標準庫。通過包管理器，可以安裝各種外掛程式。J 語言擁有常規除錯機制，還有叫做 Dissect 的可視除錯器。除了科學計算和統計分析，它還被用於關聯式資料庫管理系統如 Jd、極限編程和網路效能分析。

2011 年 3 月，J 語言採用了 GNU 通用公共許可證版本 3，從而成為自由和開源軟體，人們還可以在 Jsoftware 的商業許可證下利用原始碼。

## 文件與詞類

J 語言的文件包括在官網的 NuVoc 中，在其中將主要的字羅列為「J 原語」，並使用顏色標示出它們分別的詞類。早期的文件還有入門和字典。在 J 語言中的字，被辨識為名詞、動詞、定語（副詞和連詞）、系詞、標點、控制字。一個程式或常式，如果接受資料作為輸入並產生資料作為輸出，則被稱為「動詞」，與之相對，資料參數被稱為「名詞」。

動詞有兩種形式：只有右側一個參數的一元（monad）形式，和有左右兩側參數的二元（dyad）形式，例如在 `-1` 中減號是一元動詞，而在 `3-2` 中減號是二元動詞。J 語言預定義了很豐富的動詞，它們都自動的作用於多種資料類型之上。使用者定義的程式可以自行命名，並用在任何允許使用原始動詞的地方。無論原始動詞還是衍生動詞，它們的一元定義與二元定義，在很大程度上是獨立的。

## 起步範例

J 語言可以寫出非常精簡的程式，特別是存在重度的對符號的函式多載，以至於一些編程者將它稱為難以閱讀的唯寫語言。在電腦的終端上執行 `ijconsole`，即可進入 J 語言的 REPL 直譯器介面。

### Hello, World!

J 語言的「Hello, World!」程式：

這個 Hello World 的實現反映了 J 語言的傳統用法，就是把程式錄入到 J 直譯器對談中，顯示出表達式結果。還可以準備 J 指令碼來作為獨立程式來執行，比如在 Linux 系統上，可以編輯如下內容的一個文字檔案，並命名為比如 `test01.ijs`：

注意第一行的 `#!` 必須頂頭，這裡的 `echo` 和 `exit`，是與 Unix shell 中同名命令功能類似的動詞。然後在終端介面中執行這個檔案：

### 平均

在 J 語言中函式一般稱為動詞，例如定義一個叫做 `avg` 的動詞，計算一序列數的平均：

一元動詞 `#`「計數」（tally），總計陣列中專案的總個數。動詞 `+`「加」（plus）和副詞 `/`「插入」（insert），衍生出的動詞 `+/`，合計這個陣列的專案的總和。二元動詞 `%`「除」（divide）將這個總和除以這個總個數。而使用者定義的動詞 `avg`，用到了由連串（strand）的三個動詞（`+/`、`%` 和 `#`）構成的一個「叉子」（fork）。叉子 `(f g h) y`↔`(f y) g (h y)`，這裡的 `f`、`g` 和 `h` 指示動詞，而 `y` 指示一個名詞。

使用 `avg` 的一些例子：

一元副詞 `/`「插入」（insert），接受位於它左側的一個運算元，並產生將這個動詞應用於其參數的每個專案之間的一個動詞。就是說，`+/` 是一個動詞，定義為應用 `+` 於給它的參數的各個專案之間。計算移動平均用到的二元副詞 `\`「中綴」（infix），將作為資料參數的列表劃分成一系列的指定大小的連續專案的子列表，將所修飾動詞應用於其上，並將這些結果形成一個列表。

一元動詞 `]`「相同」（same），恆等於給它的單一右參數，常像這樣用來在賦值之後顯示變數的內容。一元動詞 `?.`「擲骰 / 固定種子」（roll/fixed seed），不同於一元動詞 `?`「擲骰」（roll），在生成資料參數專案所指定大小範圍內的亂數之時，採用固定的種子。這裡確定對矩陣按行還是按列進行平均，用到了連詞 `"`「秩」（rank），它在後面的定語章節和單獨條目中論述。

### 尋找與排序

二元動詞 `i.`「出現索引」（index of），和二元動詞 `i:`「最後出現索引」（index of last），在任何大小的陣列內尋找匹配者，並返回它的位置索引，如果未找到匹配者，則返回這個陣列的大小。例如：

在 J 語言中，排序可以按 APL 傳統的兩步驟方式，使用一元動詞 `/:`「升序索引」（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）。下面是用例：

### CSV 外掛程式

在管理員權限下，安裝用來支援 CSV 檔案的外掛程式：

一個 CSV 檔案簡單用例：

下面演示使用 J 語言編寫在管道中的過濾器，例如，在具有隱式編程機制 Unix 管道的 Linux 系統中，建立如下內容的文字檔案，並命名為比如 `filter01.ijs`：

然後在終端介面中執行如下命令列：

## 資料類型

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 語言的擴充精度整數：

這裡採用一元動詞 `o.`「π 乘以」（pi times），和一元動詞 `<.`「下取整」（floor）二者的複合，得到預期的結果。位的列表可以使用一元動詞 `#.`「基數 2」（base 2）解碼成整數。整數可以使用一元動詞 `#:`「反基數 2」（antibase 2）編碼為位的列表。

### 文字

J 語言還支援文字即字元類型。文字包圍在撇號 `'` 之間，比如 `'a'` 或 `'b'`。文字的列表，通過將多個字元用撇號包圍起來的常規字串約定來表示，比如 `'abcdefg'`。在字串內的 `''` 表示 `'` 字元本身。單個的文字，典型的是 `8` 位寬即單位元組的 ASCII 字元，此外 J 語言還支援 Unicode 文字。

不支援在文字上的數值和布林運算，但支援面向搜集的運算，比如旋轉等。使用動詞 `".`「執行・數值」（do・numbers），將位元組陣列轉換成數值；使用動詞 `":`「預設格式・格式」（default format・format），將數值轉換成位元組陣列。

### 盒裝

盒裝類型的值是 0 維純量，而不管所包含的是怎樣的資料結構。使用一元動詞 `<`「盒裝」（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 語言支援數值稀疏陣列，通過它們的下標儲存非零數值。這在非零數值相對很少的情況下，是有效率的機制。

### 其他

J 語言還支援類和物件，但是它們並非資料類型，實際上使用盒裝文字來提及類和物件，它們實為命名語境和編號語境。

此外還有一個偽類型即記憶體對映檔案，它將變數對映到檔案系統中的持久檔案。

## 簡要詞彙表

下面的表格簡要列出了常用詞彙。如果含義中用了間隔號（・）分隔，通常前者是只有一個右側參數的一元含義，後者是左右兩側都有參數的二元含義。列出的對應 APL 符號，是 Dyalog 等現代 APL 所採用的符號。

### 基本

### 數學

### 結構

### 選取

### 索引

### 算子

### 雜類

## 定語

J 語言的能力，很大程度上來自它的「定語」（modifier：修飾詞），這個範疇包括「副詞」和「連詞」：這些符號接受名詞和動詞作為運算元（operand），並以指定方式應用這些運算元。定語都可以應用於任何動詞，包括使用者寫的動詞，使用者可以寫自己的定語。

J 語言的二元動詞有**右**結合性，或稱為儘量長右作用域，即它有儘可能多的右參數。算子即定語首先應用，然後是結果的動詞。算子即定語有**左**結合性，或稱為儘量長左作用域，即它有儘可能多的左參數。

### 副詞

一元副詞 `/`「插入」（insert），副詞 `\`「字首・中綴」（prefix・infix），副詞 `\.`「字尾・外綴」（suffix・outfix），和連詞 `;.`「剪下」（cut），指定參數的諸個規則或不規則子集，並在其上執行運算。

副詞 `~`「反身・被動」（reflex・passive），其一元形式將提供給動詞的右參數重複放置在左參數位置上，二元形式將提供給動詞的左右兩個參數對換位置。

### 秩

名詞的秩（rank）是排布其原子所依據的軸的數目，即它的形狀中專案的數目。動詞的秩是它能夠在其上直接運算的右（和左）名詞參數的最高秩，典型的表示為三個原子的一個列表：`一元秩 二元左秩 二元右秩`。對副詞和連詞標示的秩，是所形成的動詞的秩。

秩在特定動詞和特定名詞的上下文下，將名詞的諸維，劃分成字首諸維的序列，稱為框架（frame）；和字尾諸維的序列，稱為單元（cell）。秩採用連詞 `"`「秩」來操縱，對應於 APL 符號 `⍤`，它有三種形式：`u"n`「指定秩」（assign），`m"n`「常數動詞」（constant），`u"v` 和 `m"v`「複製秩」（copy），這裡的 `u`、`v` 表示動詞運算元，而 `m`、`n` 表示名詞運算元。正數動詞秩，指示單元諸維的數目，負數動詞秩，指示框架諸維的數目，`_` 指示整體。

二元動詞的左右參數的框架經常是匹配的，就是說的左右參數有相同數目的單元。如果二者不匹配，有三種可以運算的情況：

1. 純量一致，如果指定了兩參數中某一側的框架為空，即秩為 `_`，這一個整體單元被應用於另一側參數的所有單元。
2. 字首一致，兩參數中有一側的短框架是另一側長框架的字首，短框架的每個單元，被應用於對應的長框架去掉字首餘下諸維形成的單元陣列的所有單元。
3. 字尾一致，兩參數中有一側的短框架是另一側長框架的字尾，這時需要以兩側加上相同正數增量的方式指定秩，使原短框架側的框架為空，原短框架的諸維形成的這一個單元陣列，被應用於原長框架去掉字尾餘下諸維形成陣列的每個單元陣列。

### 複合連詞

連詞 `@:`「在於」（at）、`@`「頂上」（atop）、`&:`「並列」（appose）、`&`「合成」（compose），是四種複合（composition）。J 語言支援叫作「勾點」（hook）和「叉子」（fork）的隱形連詞，二種隱形連詞和四種複合連詞，規定了如何將參數或將所飾動詞應用於參數的結果，提供給所飾動詞來進行應用的規則。下表列出它們的定義：

在上面表格中，`mv=: 0{v b.0`，`lv=: 1{v b.0`，`rv=: 2{v b.0`，這裡的副詞 `b.0` 給出動詞 `v` 的三個秩。在應用四種複合連詞形成新動詞的表達式中，`@:` 和 `&:`，要對第一步運算的中間結果，按所在子表達式的秩或整個表達式的秩 `_` 進行匯集（assembly），並在有需要的情況下進行框架填充，然後在這個匯整合的框架內進行第二步運算；而 `@` 和 `&`，直接在第一步運算的框架內，對中間結果進行第二步運算；在整個表達式求值結束時，最終結果在有需要的情況下要進行整體填充。

在 `x (u @ v) y` 中，一元 `u` 直接在二元 `v` 所劃分的框架內進行自己的運算。在 `x (u @: v)"v y` 中，`@:` 將二元 `v` 的運算結果，匯整合 `"v` 所指定的框架。在 `x (u & v) y`，二元 `u` 直接在一元 `v` 所劃分的兩個框架內進行自己的運算。在 `x (u &: v)"mv y` 中，`&:` 將一元 `v` 的兩個運算結果，匯整合 `"mv` 所指定的框架。

下面例子展示四種複合的中間結果的單元差異：

當連詞 `&` 的一個運算元是名詞的時候，表示「粘上」（bond），它通過向二元動詞固定提供其一個參數的值而產生一個動詞：

`&` 衍生的動詞經常作為一元動詞使用，即 `m&v y` 或 `u&n y`；如果作為二元動詞使用，即 `x m&v y` 或 `x u&n y`，左參數列示應用這個衍生動詞於右參數的次數。需要確保通過 `&` 定義的一元動詞，不出現在能夠取用左右兩個的參數的上下文中；如此定義的二元動詞，也不應該出現在只能取用一個右參數的上下文中。需要注意 `m&v`、`v/` 和 `v\` 等的左參數的作用域，有時遇到其左側的複合連詞會產生並非預期的效果，經常需要將表達式整體加以圓括號包圍。

J 語言還提供連詞 `&.:`「底下」（under）和 `&.`「對偶」（dual）。下面定義中的動詞冪 `^:_1` 表示逆運算：

`@`、`&` 和 `&.` 合稱為「緊密複合」（close composition）。現代 APL 中另有 `¨`「每個」（each），`f¨` 相當於 J 語言中的 `f &.>`。例如：

在 J 語言中，孤立的動詞序列叫做「列車」（train）， `e f g h` 意味著 `(e (f g h))`，`d e f g h` 意味著 `(d e (f g h))`；以此類推，動詞列車的一般模式 `(a b c ...)`，依賴於動詞的數目，在偶數時形式為 `(a (b c ...))`，最外層是個勾點；而在奇數時形式為 `(a b (c ...))`，最外層是個叉子；二者的內部都是可能有多層的巢狀的叉子。

叉子、`@:` 再加上 `[` 和 `]`，可以將很多常用複合寫為列車。在慣用法 `([: f g)` 中，並不實際執行的隱式動詞 `[:`「遮帽」（cap），封鎖了叉子的左分支，形成了等價於 `f @: g` 的特殊化叉子。

與現代 APL 如 Dyalog 等對照，複合連詞 `@:` 對應於同秩連詞共享 APL 符號 `⍤` 的「頂上」（atop），而 `&:` 對應於 `⍥`「上方」（over），共享 `&` 符號的「粘上」，對應於 APL 中的「綁上」（bind），APL 的「綁上」和「邊上」（beside）共享符號 `∘`，「邊上」的一元形式同於 `⍤`，而二元形式同於勾點。在《APL 字典》中，`@` 對應其 `⍥`，而 `&` 列入秩連詞 `⍤` 之內，勾點對應於符號 `⍩`「枝條」（withe），`&.` 對應於符號 `¨`。

#### 用例

下面是計算歐幾里得範數和生成數位與維度坐標一致的整數的簡單例子：

在 `coor` 中採用的圓括號包圍，使得 `@:` 處在整個表達式的最外層，從而形成了兩步驟運算；右側的第一步是圓括號包圍的子表達式，它的完全加圓括號（fully-parenthesized）形式為：`(((< @: >:) @ i.)"0)`；左側的第二步是 `{` 與複合到其上諸運算構成的子表達式，它的完全加圓括號形式為：`(((10 & #.) @ >) @ {)`。一元動詞 `{`「目錄組譯」（catalogue），應用在盒裝列表的列表之上，是接受可變數目的變長參數的典型的動詞。下面通過對圓括號包圍的子表達式加以變化，辨析秩連詞和複合連詞的特性：

下面的例子展示並聯電阻電路計算： ${\frac {1}{R_{\mathrm {total} }}}={\frac {1}{R_{1}}}+{\frac {1}{R_{2}}}+\cdots +{\frac {1}{R_{n}}}$ ，它可以如下這樣表達：

### 動詞冪

連詞 `^:` 動詞冪」（power of verb），有兩種形式：

* `^:n`，是運算元為名詞的「固定冪」。
* `^:v`，是運算元為動詞的「動態冪」。

對於固定冪 `u ^:n`，如果 `x` 缺席，`u ^:n y` 在以 `y` 為運算物件的迭代中，將動詞 `u` 應用 `n` 次；如果 `x` 存在，`x u ^:n y` 在以 `y` 為運算物件的迭代中，將動詞 `x&u` 應用 `n` 次。如果 `n` 是陣列，則按每個原子專案都執行一次動詞冪，結果的框架為這個陣列的形狀；如果 `n` 是取值為 `0` 或 `1` 的變數，則形成布林值條件執行；如果 `n` 是 `_1`，則進行 `u` 的逆運算；如果 `n` 是 `_`，則意味著「收斂」（converge），即反覆應用 `u` 直到結果不再變化。例如：

對於動態冪 `u ^:v`，如果 `x` 缺席，`u ^:v y` 在以 `y` 為運算物件的迭代中，將動詞 `u` 應用 `v y` 次；如果 `x` 存在，`x u ^:v y` 在以 `y` 為運算物件的迭代中，將動詞 `x&u` 應用 `x v y` 次。動詞冪可以形成動態條件執行，這裡的動詞 `v` 必須總是產生布林值結果，應用動詞 `u` 若且唯若 `v` 返回 `1`。進而 `u ^:v ^:_ y` 可以形成 while 迴圈構造，只要 `v` 返回 `1`，就反覆的執行 `u`，直到 `v` 返回 `0`，或者 `u` 將它的參數無變化的返回。例如：

### 動名詞

在 J 語言中，動名詞（gerund）是叫做「原子表示」的特殊盒子的一個列表，這種盒子可以像任何其他盒子一樣使用，並可以最終轉變回到要執行的動詞。關於動名詞的運算有：

* 連詞 `` ` ``「連結動名詞」（tie or gerund），建立動名詞。
* 連詞 `` `: ``「喚起動名詞」（evoke gerund），在加以運算元之後成為：
  * `` `:6 ``，將動名詞轉變成動詞列車；
  * `` `:0 ``，將轉變回來的這些動詞分別單獨應用，並將它們的結果收集入一個列表。
* 連詞 `@.`「議程」（agenda），`m @. n` 從動名詞 `m` 中，選擇出第 `n` 個原子表示，將它轉變回到動詞並執行它。

下面是動名詞簡單範例和考拉茲猜想範例：

## 定義

J 語言支援使用者進行顯式定義，和 `{{`……`}}` 形式的直接定義。下面以五種複合作為顯式定義的例子：

下面以矩陣乘法作為直接定義的例子，並順帶演示秩連詞的用法：

APL 傳統上的將內積 `Pf.gQ` 解釋為 `f/PgQ`，J 語言的矩陣乘法要求寫為 `Pf/ .gQ`，不隱含的為左運算元 `f` 附加一元 `/`。轉置也是有較大開銷的運算，不同的矩陣乘法演算法有不同的參照局部性。

* `matmul` 通過 `"(1 _)` 將 `u@:v` 的右參數從向量擴充為一般陣列，它用於右參數為行主序陣列的情況。在向量與向量列表二者諸項之間逐對的進行乘積累加運算，是 BLAS 的標準演算法。
* `inner` 採用了兩向量之間的點積運算 `u@:v"1`，它適宜直接用於右參數為列主序陣列的情況。在右參數為行主序陣列之時，需要如例子代碼這樣，對右參數陣列進行二元轉置 `0&|:`，這裡的 `0` 指示將第一軸安排至最後位置而其他軸保持原序前移。這種基於點積的實現，通常需要進一步加以迴圈鑲嵌。
* `outer` 可以看作 `matmul` 的變體，它首先對左參數陣列進行轉置，然後進行多組的向量與一般陣列之間二元的張量積運算 `v/"_1`，最後在各組結果的列表上進行 `u` 計算，每組運算之後參與其中的左右兩陣列的元素不會被其他組的運算再次存取。
* `revmul` 同 `inner` 一樣適宜直接用於右參數為列主序陣列的情況，但採用了同 `matmul` 類似的計算方法，它在乘法之前對左參數陣列和在乘法之後對結果要做轉置，`matmul` 與 `revmul` 的關係如同 $\,(\mathrm {AB} )^{\mathsf {T}}=\mathrm {B} ^{\mathsf {T}}\mathrm {A} ^{\mathsf {T}}\,$ 。`matmul` 一次性存取左參數陣列，反覆多次存取右參數陣列；`revmul` 一次性存取右參數陣列，反覆多次存取左參數陣列。

在隱式定義中，遞迴定義可以不通過名字參照自身，轉而使用動詞 `$:`「自參照」。例如遞迴的計算斐波那契數列：

`_9:` 到 `9:` 是常數動詞。動詞 `[:`「遮帽」，用在連詞 `u : v`「一元與二元定義」所應用的動詞位置上，即充任了一元動詞 `u` 或二元動詞 `v`，可分別在如下兩種情況下報錯：定義的是二元動詞，卻不適當的被用作一元動詞；或定義的是一元動詞，卻不適當被用作二元動詞。

在顯式定義和直接定義中，提供了類似其他過程語言的控制結構。這裡列出的是每個範疇內的代表性控制字：

## 索引

J 語言的索引機制採用二元 `{`「來自」（from）動詞來完成，它有兩種形式，分別為左參數為索引陣列的主軸索引，和左參數為二層或一層盒裝結構的逐軸索引，二者分別對應 APL 中，方括號內為單個軸的主軸索引選取，和方括號內為 `;` 分隔的多個軸的逐軸索引選取。

### 主軸索引

索引陣列的每個專案指定對主軸的專案單元的一個選取，將它們的結果再匯合為一個陣列。負值索引表示從末尾往前記數。在 APL 中，這種形式的索引被稱為「來自」（from），也叫做「選取」（select）或幽默地稱為「明智」（sane）索引，最早出現在 SAX（SHARP APL for UNIX）對其 `@`「來自」索引的擴充中，部份現代 APL，將它表示為符號 `⊇`。例如：

### 逐軸索引

逐軸選取可以形成子陣列，在現代 APL 中，它被表示為 `⌷`，故而也被稱為「扁方塊」（squad：squish quad）索引（indexing）或就叫做「索引」（index）函式。裝在二層盒裝結構中的，是對應諸軸的一層盒裝子結構的列表，其中每個一層盒裝子結構內都是數值列表，它對應在此軸內一個或多個專案選擇。預設全選使用名詞 `a:`「麼點」（ace）指示，它是盒裝空串列 `<0$0`。在尾部的連續多個預設全選不需要寫出。例如：

它還支援一層盒裝結構，裝在其中的是數值列表，它的元素指示每軸選取一個專案，如果單選了所有軸，則指定一個原子專案。一層盒裝結構中的這個數值列表，等價於二層盒裝結構中一層盒裝的單一數值的列表。兩種索引形式可以結合使用，即可以將盒裝結構的陣列作為給 `{` 的左參數，它按這個陣列的形狀匯合多個逐軸選取的結果。例如：

例如 `(<<1 2),(<a:;0 2 3)` 這樣的選取是合法的，將形狀不一致的選取結果匯合在一起，會導致結果值填充。

### 重排軸

重排軸也叫做二元轉置。APL 的二元轉置對軸次序的指定，類似於組合數學中置換的一行形式的柯西表示法，它被稱為「可能是 APL 編程者最後掌握的原始運算之一」。J 語言的二元轉置對軸次序的指定，不涉及將多個軸對映到結果中的一個軸的情況，使用了普通的索引形式的置換向量。在置換向量的元素個數小於陣列軸的數目之時，J 語言在置換結果中將其指定的諸軸安排在尾部，而其他軸保持原來相對次序前移。

針對向量的索引運算是不加盒裝的主軸索引。用以存取一般陣列的選取向量，需要一層盒裝來對其進行逐軸索引。置換向量 `p` 所對應的逆向置換向量是 `/:p`，對於兩個置換向量 `p` 和 `q`，則有 `/:p{q` ↔ `(/:q){/:p`。

二元轉置與索引機制有密切關聯，它有兩個重要性質：

* 兩次連續的二元轉置，可以變換成等價形式：`p|:q|:A` ↔ `(p{q)|:A`，即先將後者置換向量 `p` 對前者置換向量 `q` 進行置換，然後用結果的置換向量做一次二元轉置。
* 對二元轉置後的陣列，進行原子專案的選取，可以變換成等價形式：`(<k){p|:A` ↔ `(<(/:p){k){A`，即先用置換向量 `p` 的逆置換向量 `/:p`，對選取向量 `k` 進行置換，然後用結果的選取向量來選取未轉置陣列。

下面是演範例子代碼：

## 範例

### 帕斯卡三角

下面例子形成帕斯卡三角的二項式係數的直接定義，並順帶展示基本的矩陣與盒裝運算：

二項式係數也可以寫成隱式定義形式：

### 簡易圖表

下面是基於二元副詞 `/`「形成表格」（table），製作條形圖和散點圖的簡易圖表例子:

這裡用到的 Unicode 方塊元素字元也出現在 IBM PC 頁碼 437 之中。

這裡的 `scatterChart` 可以使用二元副詞 `}`「修改」（amend）來實現：

### 對角線選取

APL 的二元轉置，在多個軸對映到結果中的一個軸的情況下，將其依次安排到前導位置上並進行對角線選取。下面基於一元動詞 `I.`「真值位置索引」，定義進行對角線選取的動詞 `diag`，它的左參數是布林值列表，其中的真值 `1` 指示與其位置對應的軸，要依次安排在前導位置上並進行對角線選取，其他的假值 `0` 所對應的軸相對位置不變。

這裡局部定義了 `s`，它的左右參數同於給 `diag` 的參數，它生成二元轉置需要的置換向量，這是由要安排到前導位置上的那些軸的位置索引，和餘下其他軸的位置索引串接而成。這裡的 `{.~ $@$` 以右參數的諸軸數目選取左參數，用來在左參數的真值和假值的總數小於右參數的諸軸數目之時，對左參數填充上假值。

接著局部定義了 `t`，它的左參數是給 `diag` 的布林值列表中真值 `1` 的個數，右參數是要對其指定數目的前導軸進行對角線選取的陣列，它生成對角線選取所需要的一層盒裝選取列表。這裡的 `(<./)@({. $)` 選取出要進行對角線選取的前導諸軸的最小長度，用 `i.` 形成這個長度的整數數列，再用 `#&1@[` 形成其長度為左參數的全為 `1` 的列表，通過 `*/` 在二者之上形成表格矩陣。

最後的表達式先進行指定的二元轉置，再對其結果進行相應的對角線選取。下面是簡單用例：

### 快速排序

J 語言提供的排序機制基於了穩定排序演算法，下面的例子代碼是快速排序的直接定義：

這裡定義一個動詞 `cmp`，它通過逐個做兩個數的差並取其符號，得到取值為 `_1`、`0` 或 `1` 的平衡三進位值。`cmp` 將作為左運算元傳遞給副詞 `quicksort`。

在 `quicksort` 的定義中，向局部變數 `s` 賦值的表達式，第一步隨機選擇支點（pivot）運算，首先計算 `?#y`，生成在資料總個數範圍內的亂數，接著在其上計算 `{~`，選擇出在亂數指定的位置上的支點值；它的第二步運算，將運算元 `u`，應用到其左參數的資料列表，和右參數的支點值二者之上。

隨後是串接分治運算結果，首先將平衡三進位值列表，分別與 `0` 做逐項的三分法比較，得到三個布林值列表；然後以這種列表中的 `0` 和 `1` 作為件數，複製出資料列表的符合這個條件一個新的子列表，其中兩個作為參數傳遞給遞迴呼叫進行排序。

下面的快速排序實現，展示了隱式編程，即將函式複合在一起，而不顯式的參照任何變數，不提及要應用於其上的形式參數。這裡將前面代碼中向局部變數 `s` 賦值時所求值的表達式改為隱式定義，進而以作為勾點的第一步運算的方式，代入參照這個變數的表達式之中，並且採用勾點的參數複製機制消隱了形式參數 `y`：

提供給連詞 `^:` 的左側運算元，外層是個一元勾點，它將提供給它的單一右資料參數，重複放置在它的左資料參數位置上。這個外層一元勾點的第一步運算，是生成平衡三進位值列表的巢狀的二層一元勾點 `(u ({~ ?@#))`；而外層一元勾點的第二步運算，將生成的三個子列表串接起來。生成三個子列表的表達式，以資料列表是作為左參數，以平衡三進位值列表作為右參數；這裡的三個二元勾點首先生成布林值列表，接著進行對換了左右參數位置的二元複製運算，最後它們中有兩個通過自參照 `$:` 進行了遞迴呼叫。

這個定義中的 `$:` 是在這個副詞的私有語境內呼叫的動詞，所以不像前面直接定義那樣需要加上運算元 `u` 以副詞形式來呼叫。這裡沒有對字串長度小於等於 `1` 的情況進行處理，這是因為迭代運算在條件不滿足時返回初始值，也就是返回這個字串本身。將 `cmp` 的表達式，代入定義中的左運算元 `u`，就能定義出動詞，同時也不再需要外在的採用直接定義的形式。

將一元勾點替代為左分支為 `]` 的叉子，形成的動詞列車更具可讀性：

下面的例子定義基於一元 `/:` 進行字串比較的 `cmp`：

在這個 `cmp` 定義中，`/:@;` 先將兩個字串參數進行盒裝串接，然後一元 `/:` 給出二者的升序索引，二者之間為升序或相同時為 `0 1`，而二者為降序時為 `1 0`；至此是升序還是相同仍需區分，`-.@-:` 判斷兩參數是否為「不相同」，不相同時為 `1`，而相同時為 `0`。這裡的副詞 `;._1`「自有區間」，使用字串的第一個字元作為分隔符，對字串進行劃分並去除分隔符，然後應用所修飾的動詞於這些子字串之上。

### 全排列

下面的例子給出 `n` 個專案的所有置換的有次序的矩陣。首先定義名詞 `p3`，它是長度為 `3` 的排列矩陣：

這裡用到了動詞：`A.`「易位詞」（anagram），`x A. y` 的左參數 `x`，指定了長度為 `#y` 的所有置換中給特定一個置換的編號，據此編號置換 `y` 的專案。這裡求全排列的數目，用到了一元動詞 `!`「階乘」。接著在 `p3` 的基礎上，實現長度為 `4` 的排列矩陣：

這裡的 `{"(_ 1)`，對其右側的 `4`×`4`「奇妙」矩陣的每一行，按照其左側加工後的 `3` 元素全排列，對其後面的 `3` 個元素進行排列。這一步寫出的排列動詞的結果是三維陣列，將它重製形狀為矩陣：

二元動詞 `$` 的左參數的值為 `(!y) , y`，這裡的 `y` 是給排列動詞的資料參數；而它的右參數是用一元動詞 `,` 將三維陣列散開後形成的一個向量。

然後將其中的 `p3`，替代為遞迴的自呼叫 `$:@-&1`；並通過名詞秩，形成常數動詞 `(1 0$0)"_`，設定長度為 `0` 時的基礎值為 `1 0$0`：

最後將遞迴形式改為迭代形式，可採用連詞 `F..`「單結果正向摺疊」（fold single forward），使用它需要事先安裝外掛程式 `dev/fold`：

如果不採用連詞 `F..`，可以基於一元副詞 `/`「插入」而自行實現摺疊算子：

### 生命遊戲

在 J 語言中，提供了二元副詞 `;.±3`「子陣列」（subarrays），它是 `;.`「剪下」（cut）的三種形式之一，也被稱為密鋪（tessellate）或鑲嵌（tile）。`x(u;._3)y` 應用動詞 `u` 於由 `x` 指定的 `y` 的有相同形狀的每個正規鑲嵌之上。`;.3` 與之類似，但不丟棄結果中不完整的鑲嵌。

現代 APL 所使用的二元算子 `⌺`「模板」（stencil），在邊緣的處理上不同於 J 語言的鑲嵌，它要求鑲嵌子陣列每個軸的中心，在長度為奇數時是 `y` 的元素，在長度為偶數時在其元素之間，並且用填充（fill）元素填滿超出的部份，它的預設移動步長是 `1`。下面在 `;._3` 的基礎上，利於二元動詞 `{.`「採取」（take）的填充特性，定義一個 `stencil` 實現：

這個定義只向運算元提供一個右參數即鑲嵌子陣列，不提供同每個子陣列對應的諸軸填充數目作為左參數，APL`⌺` 算子提供它，意圖在需要時籍此移除填充。這裡將鑲嵌規定矩陣定義為右運算元 `n`，其第 1 行是子陣列的每軸長度，第 2 行是每軸的移動步長，這個行次序與 `;.±3` 的規定相反。這裡的 `p` 是給 `;._3` 的鑲嵌規定矩陣，`r` 是每軸在頭部和尾部的填充數量，`s` 是正值控制尾部填充，`t` 是負值控制頭部填充。在下面的簡單用例中，數值陣列的填充元素是 `0`：

下面實現康威生命遊戲，它是基於 Moore 鄰域的一種細胞自動機:

這裡的實現演算法，將生命遊戲規則合併入一個單一表達式中，它由 Arthur Whitney 提出。演算法的第一步驟用 `+/@,` 合計每個格點及其周圍格點中 `1` 數目，並將它局部儲存在 `s` 中。第二步驟將為前面的結果與 `4` 做相等比較，再與當前狀態 `y` 做邏輯與運算，只有在當前格點為 `1`，而且周圍格點合計為 `3` 的情況下，當前格點得到真值 `1`。第三步驟用 `s` 減去前面的結果真值，再與 `3` 做相等比較。在這個最終結果中，當前格點得到真值 `1` 有兩類情況：⑴它在 `s` 中的值為 `4`，並減去了真值 `1`，這就是第二步驟運算所選定的情況；⑵它在 `s` 中的值為 `3`，並減去第二步驟運算在這種情況下必然得出的假值 `0`，這又可細分為兩種情況：當前格點為 `0`，而且周圍格點合計為 `3`；或者當前格點為 `1`，而且周圍格點合計為 `2`。這裡用到的 Unicode 字元位於幾何圖形區段中。

這個演算法可以寫為隱式定義形式：

在 J 語言中，實現以遞推關係定義的序列，避免出現 $\,O(n^{2})\,$ 的時間複雜度，可以採用連詞 `F:.`「多結果正向摺疊」（fold multiple forward），使用它需要事先安裝外掛程式 `dev/fold`；它不輸出左參數的初始值，如果提供的右參數為空值，它的輸出為空值，否則它輸出每次迭代的結果。上例中的迭代算式可以覆寫為：

如果不採用連詞 `F:.`，可以自行實現輸出中間結果的摺疊算子：

在這裡的 `foldlist` 中，將 `r=. '' [ a=. x` 改為 `r=. u a=. x`，則 `(< , <foldlist(life@])&(7$0))` 可改為 `<foldlist(life@])&(7$0)`。

### 鍵分組

在 J 語言中，提供了二元副詞 `/.`「鍵分組」（key），它按左參數中的唯一鍵，對右參數進行分組（group）或稱為分割區（partition），並將所修飾動詞應用到這些分組之上。分組次序同於一元副詞 `~.`「唯一值」處理結果的次序，它除去匹配前面出現過的專案的任何專案。下面在它的基礎之上，定義對應現代 APL 使用的二元算子 `⌸`「鍵分組」（key）的一個副詞，它將所修飾動詞應用在唯一鍵和相應的分組二者之上，它還具有一元和二元兩種形式：

它的二元形式的左參數含有唯一鍵，而右參數是要分組的資料；它的一元形式的右參數含有唯一鍵，所分組的是右參數諸專案的索引值。下面是這個鍵分組副詞所適用的動詞的簡單範例：

下面的例子通過鍵分組來找到一個單詞列表中的易位詞：

### 亂數

在 J 語言中，提供了二元動詞 `I.`「區間索引」，它左參數 `x` 必須是有次序的，從而定義了 `1+#x` 個區間，除了最後一個之外的每個區間，都含有並結束於 `x` 的一個專案，而最後一個結束於正無窮，第一個開始於負無窮；它應用於右參數 `y`，給出 `y` 所位於的區間的索引。

下面的例子產生符合指定離散概率分布的亂數列表，這裡定義了動詞 `ran`，它依據左參數 `x` 給出的正實數向量中的這些權重，從 `i.#x` 中選取出由右參數 `y` 指定個數的亂數列表：

這裡首先通過 `?@$&0`，生成指定數目的在區間 `(0,1)` 中的隨機浮點數，它也可以寫為等價的 `?@($ 0:)`。然後在叉子 `+/\ % +/` 中，使用一元副詞 `\`「字首」修飾動詞 `+/`，從而計算權重向量的字首和，再用字首和除以總和得出累積分布函式。`+/\`、`<./\` 和 `>./\`，是 J 語言會對其進行速度最佳化的特殊組合。最後通過區間索引，在有隨機浮點數落入特定區間的時候，生成這個區間對應的隨機整數。

動詞 `ran` 的表達式是個二層二元勾點，外層勾點的第二步運算只應用到右參數上，它的第一步運算即內層勾點，整體修飾了二元副詞 `~`「被動」而對換了兩個參數的位置。內層勾點的第二步運算 `+/\ % +/` 只應用到實際上的左參數上，它的第一步運算 `I.` 修飾了 `~`，而將前面單獨針對左右兩參數的運算結果，再次對換回到原先的左右位置上。

下面是將區間索引和鍵分組結合起來的例子，演示了林德伯格－列維中心極限定理:

這裡定義的 `summary` 局部賦值了兩個局部變數 `l` 和 `r`，可以將這兩個局部賦值去掉，並將這兩個局部變數的出現替代為運算元 `m` 和 `n`，如此對它的呼叫將變成 `(80&(0 summary 1))` 這樣的形式。接下的代碼結合前面兩個例子，採用了不同於上例連續型均勻分布的其他分布作為獨立同分布，和不同的樣本平均：

### SQLite 外掛程式

在管理員權限下，安裝操縱 SQLite 資料庫的外掛程式：

SQLite 資料庫的簡單用例：

### 字典類

J 語言採用命名語境實現類，採用編號語境實現物件，下面範例建立字典類：

在家目錄中建立一個 `dict.ijs` 檔案並錄入上述代碼，接著以如下代碼建立字典物件並對其進行檢視和簡單操作：

## 參見

* 秩 (J 程式語言)

## 參照

## 外部連結

* 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 － APL Wiki （頁面存檔備份，存於網際網路檔案館）
* 郭平欣譯 J 字典 （頁面存檔備份，存於網際網路檔案館）