J言語
APLの開発者であるケネス・アイバーソンがAPLの不満点の改善や、普及しやすいよう特殊文字を排除することを目的として開発した。 基本的にワンライナーでスクリプトを書く。
J言語の文法に関して
Forthは左から右にスタックを表現している言語であり なので右結合で処理していく。
最も右端に記述されたものからスタックに積まれていく。 式の左辺は終わりでも始まりでもない。ルートである。式は、収束したり分岐したりする枝を持つツリーである。それは命令のリストではない。
連結指向言語では、スタック上に引数が存在していることが想定されているため関数呼び出しに引数がない
J言語でも同様にverbが monad / dyad の2つの系統しか存在しないのはForthのような暗黙な引数取得を可能にするための仕様だろう。 table:リテラル
種類 記法 つまり
文字 'Hello, World'
小数 0.4
e指数 3e100 300
複素数 3j5 3+5i
有理数(分数) 1r3 1/3
基数指定 2b111, 16bff 2進数, 16進数
verb(動詞)
verb とは + 等の演算子や他の言語の関数にあたるもの
常に右結合、よって 乗除算が優先されるとかはない
よって J言語のコードを見たときは、まずは右から左に向かって読んでいく。
J言語にビルドインされたものは「原始動詞」
原始動詞のの二文字目は . か:なので、動詞の区切りとしての目印となる。
「関数」ではなく動詞?
J言語の verb と他言語の「関数」の違いの一つは、引数の数
verb は、引数が 1 個の monad と引数が 2 個の dyad だけ
同じ動詞でも monad/dyad で意味が変わる
同じ動詞でも引数が両側にあるか、片側にあるかで動作が変わる
3 個以上の値を渡したい場合は、配列やボックスを使う
動詞の種類は2つある
単項演算子(monad)
片側形(monadic)
動詞の作用を受ける名詞(noun)が右側だけにある
右側に一つだけ付く → - y
二項演算子(dyad)
両側形(dyadic)
動詞の作用を受ける名詞(noun)が両側にある
左右に一つずつ → x - y
J言語は英文法を意識したような言語構成のようだ。
動詞と副詞があり、 動詞の右側に副詞で修飾すると、新たな動詞となる。
さらに接続詞で2つの名詞や動詞を連結してさらなる作用を表現できる。
code:area.ijs
NB. 例えば以下のJ式は「area is 3.14 times square of radius.」という英文に相当する
area =. 3.14**:radius
英語の「S+V」のように最も行いたい作用「V」が最初に来る
右から左に解釈される所以?
接続詞の動詞の合成
& と @ の2種類がある。
接続詞&
(m&v)は、(noun)値mをvの左引数として与えることによって、両側系vから片側系を作る。
逆に
(u&n)は、動詞uの右引数に(noun)値nを与えることで、両側系uから片側系を作る。
code:and_conjjunction.ijs
triple=.3&* NB. 3 * ... を triple として定義
triple 5
15
NB. @では同じことができない
triple=.3@*
|domain error
| triple=.3 @*
まとめると
m&v y は m v y
v&m y は y v m
よって & は両側系の動詞 v に対して引数を部分適応したものを作成するための表記法
接続詞@
u@v は動詞 u と v の合成を形成する。
オペランドuは常に、vの各適用結果に対して単項式に実行される。
つまり $ f(g(x))を作りたいときに @ を使う ← f@g
ワンライナー的に使うのが多いは @ だろう
ただし & でも $ f(g(x))は作れる。なぜ?分けた意味は?
フックとフォーク
複数verbを並べた際の実行ルール
集合$ Aから$ Bへの対応を$ \Gamma とするとき
$ a \in Aに対して定まる$ Bの部分集合を$ \Gamma(a)と書いて「$ aの$ \Gammaによる像」と呼ぶ
対応関係が1対1のとき?写像という
$ A → f(a) →B→g(b)→Cのとき、$ A→Cの写像$ g(f(a))が定まる
これを合成写像$ g\circ fと表す
単に合成関数を考えるとこれだけで良いのだが、J言語はmonad/dyadの2種類ある!
$ gが片側系のとき
$ (g \circ f)y = g \circ (fy) → (g@f)y = (g&f)y
$ gが両側系のとき
$ ... = y \space g \circ (fy) → (gf)y
のように2種類の解釈ができる
$ g \cdot f全体が両側系のとき3通りの結合の可能性があるため、接続詞で区別する
$ g \space (x \space fy) → $ fが両側系で$ gが片側系のとき → x(g@f)y
$ (fx) \space g \space (fy) → $ fが片側系で$ gが両側系 → x(g&f)y
$ x \space g \space (fy) → $ fが片側系で$ gが両側系 → x(gf)y
フックとは上記の$ y \space g \cdot (fy), \space x \space g \space (fy)のパターンに特別に付けられた名前。
J言語の構文上、フックの記述には (..)で囲まないと正しく解釈されない
()がないと右側から順に個別の片側関数として評価され、動詞が合成されない
2つの片側関数$ f, h1つの両側関数$ gがあるとき
$ (hy) \space g \space (fy) → (hgf)y
$ (hx) \space g \space (fy) → x(hgf)y
この変換ルールがフォーク
フックに左側にさらに片側関数$ hが追加するとどうなるか?と考えると覚えやすい
フックの例
code:hook.ijs
(% +/) 3 8 5 NB. フックの場合
0.1875 0.5 0.3125
+/ 3 8 5 NB. フックの動作を分解
16
3 8 5 % 16 NB. フック第2段階(結果同じ)
0.1875 0.5 0.3125
% +/ 3 8 5 NB. ()をつけないと % 16 と解釈され1/16が計算される
0.0625
まとめ
フック(2個並べた場合)
(g f) y → y g (f y)
x (g f) y → x g (f y)
フォーク(3個並べた場合)
(f g h) y → (f y) g (h y)
x (f g h) y → (x f y) g (x h y)
トレイン(4個以上並べた場合)
code:train.j
a b c d e f
a b c (d e f) NB. 1「フォーク」によって (d e f) が一つの動詞扱いになる
a (b c (d e f)) NB. 2「フォーク」によって (b c (d e f)) が一つの動詞扱いになる
(a (b c (d e f))) NB. 3「フック」によって (a (b c (d e f))) が一つの動詞扱いになる
$(shape) と # (tally) と rank(#@$)
J言語独特の機能
$ (shape)
名詞の形状を返す動詞
code:shape.ijs
(];$)1 NB. スカラーは軸を持たないのでNULL
+-++
|1||
+-++
(];$)>:i.3 NB. 1軸に3要素もつベクトルなので3
+-----+-+
|1 2 3|3|
+-----+-+
(];$)>:i.3 2 NB. 3行2列のテーブルなので 3 2
+---+---+
|1 2|3 2|
|3 4| |
|5 6| |
+---+---+
(];$)>:i.2 2 2 NB. 2行2列2枚なので 2 2 2
+---+-----+
|1 2|2 2 2|
|3 4| |
| | |
|5 6| |
|7 8| |
+---+-----+
# (tally)
名詞のアイテム数をカウントする動詞
code:tally.ijs
(];#)1 NB. スカラーなのでアイテム数1
+-+-+
|1|1|
+-+-+
(];#)>:i.3 NB. 3要素のベクトルなので3
+-----+-+
|1 2 3|3|
+-----+-+
(];#)>:i.3 2 NB. ベクトルが3行あるので3
+---+-+
|1 2|3|
|3 4| |
|5 6| |
+---+-+
(];#)>:i.2 2 2 NB. 2行2列のテーブルが2枚あるので 2
+---+-+
|1 2|2|
|3 4| |
| | |
|5 6| |
|7 8| |
+---+-+
# @$ (rank)
「Shapeのアトムの数と同じ軸の数」を名詞のランクと呼ぶ。
code:rank.ijs
(];#@$)1 NB. スカラーの rank は 0
+-+-+
|1|0|
+-+-+
(];#@$)>:i.3 NB. ベクトルの rank は 1
+-----+-+
|1 2 3|1|
+-----+-+
(];#@$)>:i.2 5 2 NB. テーブルの rank は 2
+----------+-+
|1 2 3 4 5|2|
|6 7 8 9 10| |
+----------+-+
(];#@$)>:i.3 2 5 NB. テーブルのテーブルの rank は 3
+--------------+-+
| 1 2 3 4 5|3|
| 6 7 8 9 10| |
| | |
|11 12 13 14 15| |
|16 17 18 19 20| |
| | |
|21 22 23 24 25| |
|26 27 28 29 30| |
+--------------+-+
アレイ
いわゆる配列だが、機能拡張されているため以下のような用語
table:Jでのarray
ランク J言語 一般的には Jでの記述
0 アトム スカラー (リテラル)
1 リスト ベクトル (1次元配列) スペースで区切ればOK → 2 3 4 ...
2 テーブル 行列 (n次元配列) 動詞$ で 2 3 $ 1 2 3 4 5 6 とか書く
code:foo.ijs
NB. 動詞 $ で2行3列のテーブル(行列)を作る
2 3 $ 1 2 3 4 5 6 7 8 9
1 2 3
4 5 6
code:九九.ijs
]x =. 1 + i.9 NB. 1から9までのリスト
1 2 3 4 5 6 7 8 9
x */ x NB. 副詞 / を組み合わせて九九のテーブル
1 2 3 4 5 6 7 8 9
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81
ボックス (Box)
Go言語でいう interface{} 的な入れ物。
すべての名詞を型に関わらず格納できる箱
ボックス自体も入れ子にできる
単項< でボックス化
単項> でボックスから取り出す
code:box.ijs
]a=: <567
+---+
|567|
+---+
]b=: <'yeah'
+----+
|yeah|
+----+
<1 4 1 4 2 1 3 5 6
+-----------------+
|1 4 1 4 2 1 3 5 6|
+-----------------+
<<'box in box' NB. ボックスの入れ子
+------------+
|+----------+|
||box in box||
|+----------+|
+------------+
(<_1.23) , (<'abc') , (<1 7 3 2) , <<100
+-----+---+-------+-----+
|_1.23|abc|1 7 3 2|+---+|
| | | ||100||
| | | |+---+|
+-----+---+-------+-----+
a NB. ボックスから取り出す
567
b
yeah
><<<'hey' NB. ボックスの演算繰り返し
+---+
|hey|
+---+
両側系;でボックス化しながら結合できる
code:box2.ijs
1 ; 2 ; 3
+-+-+-+
|1|2|3|
+-+-+-+
'Pi' ; 'is' ; 3.14159
+--+--+-------+
|Pi|is|3.14159|
+--+--+-------+
参考書籍
入門記事(引用元)
網羅的にまとまっていて分かりやすい。
J言語公式サイトにある1からJ言語を学ぶ(恐らく)最も丁寧な公式記事
ネットに散在する記事を集めるなら、まずはこれを順に読んでいくのが良いかもしれない
ブラウザで試せるプレイグラウンド
2024年現在も活動しているようだ。
APL/J言語 の検索結果 - niming538の日記
J言語をパースする例
公式サイトとリポジトリ
公式Wiki
マイナー言語なので公式サイトの Wiki が最も参考になる
用語集
関連