はじめに
プログラミング言語 J を使ってFizzBuzzを作ったので、その解説をします。
J言語はとても面白いので、使ってない人もぜひ読んでみてください。
J言語とは
変態の使うプログラミング言語です。ひたすら記号の羅列で、まず読めません。負の数を表すのに_5
のように-(ハイフン)
ではなく_(アンダースコア)
を使ったり、コメントを表すのがNB.
だったりと、クセの強い言語です。
そのかわり、慣れてくるとかなり短く記述できる、便利な言語です。配列の処理に優れていて、総和や総乗を求めたり、配列同士で演算したりすることが簡単にできます。対話型で実行でき、手軽さもあります。
マイナーですが、素晴らしい言語です。みんな使うべきです。
※ 個人の感想が含まれています。
実行環境
J言語は、Windows、MacOS、Android、iOSなど、様々なプラットホームで実行できます。
私は J Android を使用してAndroidで実行しています。
J言語の環境は、iOSでなければJ言語のホームページからダウンロードできます。
インストールのページから最新バージョンのリンクに飛び、そのページの Download and Install にあるリンクから、それぞれのプラットホームにあったものをダウンロードし、Jシステムをインストールします。
たとえば、Androidならapkファイルをダウンロードしてインストールできます。
iOSの場合は、AppStoreからインストールできます。
ただし、iOS版はアップデートされておらず、バージョンがだいぶ古いので注意です。
FizzBuzz
J言語でFizzBuzzを作る方法はいろいろありますが、私が作ったFizzBuzzがこちらです。
FizzBuzz=: 'FizzBuzz'&(":@]`(4:{.[)`(4:}.[)`[@.((0:=3:|])++:@(0:=5:|])))&>:&i.
J言語はFizzBuzzを1行で書けます。しかし、パッと見ただけでは何を書いてるのか全然わかりませんね。私もわかりません。
FizzBuzz 15
のようにFizzBuzz
のうしろに適当な整数をつけて実行すると……
FizzBuzz 15
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
ちゃんとFizzBuzzが出力されます。
解説
J言語の品詞
FizzBuzzを解説する前に、少しJ言語の説明をします。
J言語では、ほかの言語で演算子やリテラルと呼ばれているものを、動詞や名詞と呼びます。
名詞は、数値や文字列などを指します。たとえば、123
や'Hello'
、1 1 2 3 5 8 13 21 34 55
(配列)などがあります。
動詞は、関数のように引数を受けて計算するものです。足し算や掛け算などをする記号や文字を指します。
動詞に引数を渡す方法は2つで、(動詞) y
のように右から1つ渡す方法と、x (動詞) y
のように左右から2つ渡す方法があります。
ほかにも接続詞というものがあります。これは動詞や名詞をつなげて、新たな動詞を作るものです。たとえば、2倍する動詞+:
と2乗する動詞*:
を接続詞@
でつなげて、2乗してから2倍する動詞を作ることができます。
NB. 6番目の電子殻(P殻)に収用できる電子数
(+: @ *:) 6
72
副詞というものもあります。これは日本語と同じで、動詞を修飾するものです。たとえば、足し算をする動詞+
に、副詞/
をつけることで、総和を求める動詞+/
を作ることができます。
NB. 114 + 514 + 191 + _9
+/ 114 514 191 _9
810
動詞を作る
J言語では、自分で動詞を作ることができます。ほかの言語でいうところの、関数を作るようなことです。
FizzBuzzでは、様々な動詞や名詞、副詞を組み合わせて、FizzBuzz
という一つの動詞を作っています。
フォーク
((動詞a) (動詞b) (動詞c))
このように、動詞3つを接続詞なしでつなげて動詞を作ることをフォークといいます。
(フォーク) y
というふうに引数を1つ渡した場合は
((動詞a) y) (動詞b) ((動詞c) y)
と評価され、動詞aと動詞cがそれぞれ引数を受け取って計算し、計算されたそれぞれの値を動詞bが受け取って計算します。
x (フォーク) y
と引数を2つ渡した場合も
(x (動詞a) y) (動詞b) (x (動詞c) y)
と評価され、同じように計算されます。
NB. 並列の合成抵抗
20 (* % +) 5 NB. 積÷和(%は割り算の動詞)
4
右から処理する
J言語では右から順番に処理します。そのほうがなにかと都合がいいんです。
たとえば、3*3-4
は3-4
が先に計算されるので_3
になります。
解説
では、FizzBuzzを右から順番に見ていきます。
FizzBuzz =: 'FizzBuzz' & ( ": @ ] ` ( 4: {. [ ) ` ( 4: }. [ ) ` [ @. ( ( 0: = 3: | ] ) + +: @ ( 0: = 5: | ] ) ) ) & >: & i.
i.
0 から (引数)-1 までの整数配列を作る動詞です。
&
動詞と動詞、動詞と名詞を繋げる接続詞です。
>:
インクリメントする動詞です。i.
によって作られた0 1 2 ……
のような配列を、1 2 3 ……
のように、それぞれの要素をインクリメントします。
&
接続詞です。
(":@]`(4:{.[)`(4:}.[)`[@.((0:=3:|])++:@(0:=5:|])))
FizzBuzzしてる部分です。あとで解説します。
&
接続詞です。
'FizzBuzz'
文字列です。FizzBuzzしてる部分の左側の引数になります。
=:
動詞や名詞に名前をつける連結詞です。変数や関数を定義するようなものです。副詞や接続詞などにも名前をつけることができます。
FizzBuzz
=:
の右側の動詞の名前です。
つまり、1 から 引数として与えられる整数 までの整数配列と文字列'FizzBuzz'
を、FizzBuzzしてる部分の引数として渡す動詞を、FizzBuzz
という名前で定義しているということです。
FizzBuzzしてる部分
FizzBuzzしてる部分の解説をします。
( ":@] ` (4:{.[) ` (4:}.[) ` [ @. ((0:=3:|])++:@(0:=5:|])) )
(動詞0) ` (動詞1) ` …… @. (条件)
接続詞の`
は、動詞どうしをつなげて動詞の配列を作ります。
また接続詞@.
は、左側の動詞の配列から、右側に与えられるインデックスの位置の動詞を返します。
つまりこの構文は、条件の部分が 0 なら動詞0を、1 なら動詞1を、…… というふうに実行します。
FizzBuzzしてる部分では、":@]
が動詞0、(4:{.[)
が動詞1、(4:}.[)
が動詞2、[
が動詞3、((0:=3:|])++:@(0:=5:|]))
が条件にあたります。
条件: ((0:=3:|])++:@(0:=5:|]))
条件の部分にはフォークが使われています。
フォークしている動詞は、(0:=3:|])
と+
と+:@(0:=5:|])
の3つです。
(0:=3:|])
を動詞a、+
を動詞b、+:@(0:=5:|])
を動詞cとして解説します。
条件: 動詞a: (0:=3:|])
ここにもフォークが使われています。
0:
と=
と3:|]
がフォークになっていて、さらに3:|]
のなかで3:
と|
と]
がフォークになっています。
]
右の引数をそのまま返す動詞です。FizzBuzzしてる部分の右の引数はi.
などを使って作った1 2 3 ……
のような整数配列なので、それが返ります。
|
右の引数を左の引数で割った余りを計算する動詞です。
3:
3 を返す動詞です。引数になにを渡されても、絶対に 3 しか返しません。
=
右の引数と左の引数が等しければ 1 を、そうでなければ 0 を返す動詞です。
0:
0 を返す動詞です。引数になにを渡されても、絶対に 0 しか返しません。
動詞aの計算結果は、引数を3で割った余りが0なら 1、そうでなければ 0 になります。
つまり、3の倍数なら 1、そうでなければ 0 になります。
条件: 動詞c: +:@(0:=5:|])
(0:=5:|])
ここはさっきとほとんど同じです。5の倍数なら 1、そうでなければ 0 になります。
@
動詞どうしをつなげる接続詞です。
+:
引数を2倍する動詞です。
つまり動詞cの計算結果は、5の倍数なら 2、そうでなければ 0 になります。
条件: 動詞b: +
動詞aと動詞cの結果を足します。
つまり条件の部分は、3の倍数かつ5の倍数なら 3、5の倍数なら 2、3の倍数なら 1、それ以外なら 0 になります。
したがってFizzBuzzしてる部分では、整数配列の要素が3の倍数かつ5の倍数なら動詞3を、5の倍数なら動詞2を、3の倍数なら動詞1を、それ以外なら動詞0を実行します。
動詞0: ":@]
]
右の引数をそのまま返す動詞です。つまり整数配列です。
@
接続詞です。
":
数値を文字列を変換する動詞です。'Fizz'
や'Buzz'
は文字列なので、1
や4
などの数値も文字列に変えなければうまくいきません。
つまり動詞0は、引数の数値を文字列に変換します。
動詞1: (4:{.[)
ここにもフォークが使われています。
[
左の引数をそのまま返す動詞です。FizzBuzzしてる部分の左の引数は文字列'FizzBuzz'
なので、それが返ります。
{.
配列の要素を取り出す動詞です。配列の要素を指定された数だけ前から取り出して、新たな配列を作ります。
4:
4 を返す動詞です。
動詞1は、'FizzBuzz'
の前から4つを取り出します。
つまり、'Fizz'
を返します。
動詞2: (4:}.[)
ここにもフォークが使われています。
J言語は、フォークのおかげで短く書けるといっても過言ではありません。
[
左の引数をそのまま返す動詞です。つまり'FizzBuzz'
です。
}.
配列の要素を落とす動詞です。配列の要素を指定された数だけ前から落として、新たな配列を作ります。
4:
4 を返す動詞です。
動詞2は、'FizzBuzz'
の前から4つを落とします。
つまり、'Buzz'
を返します。
動詞3: [
動詞3は、左の引数を返します。
つまり'FizzBuzz'
をそのまま返します。
したがってFizzBuzzしてる部分は、整数配列の要素が3の倍数かつ5の倍数なら'FizzBuzz'
を、5の倍数なら'Buzz'
を、3の倍数なら'Fizz'
を、それ以外なら文字列に変換した数値を返します。
これでようやくFizzBuzzができました!
あとは整数を指定すれば、1からその整数までの配列が作られて、その要素がFizzBuzzに変換されていきます。
追記(2020/12/27)
フォークの左の部分には名詞を使うこともできます。
なので、3:
や5:
は、3
や5
というふうに、単に数値に置き換えることができます。
FizzBuzz=: 'FizzBuzz'&(":@]`(4{.[)`(4}.[)`[@.((0=3|])++:@(0=5|])))&>:&i.
ちなみに
J言語はif文やfor文も使えます。
FizzBuzz =: 3 : 0
for_i. >: i. y do.
if. 0 = 15 | i do.
echo 'FizzBuzz'
elseif. 0 = 3 | i do.
echo 'Fizz'
elseif. 0 = 5 | i do.
echo 'Buzz'
else.
echo i
end.
end.
)
こっちのほうが読みやすい。
おわりに
最後まで読んでくださって、ありがとうございます。パズルみたいで楽しくなかったですか?
この記事を読んで、J言語に少しでも興味を持ってもらえたらうれしいです。
参考サイト
Jsoftware
J Software - J 言語
J言語基礎講座
Rubyist のための他言語探訪 【第 12 回】 APL と J
J言語の使用によるASCII文字の地獄への手引き - TopCoderとJ言語と時々F#
J言語 カテゴリーの記事一覧 - (保存用) 檜山正幸のキマイラ飼育記 メモ編
J言語でFizzBuzz - ふるつき
J言語のエッセンスとクイックレファレンス そして講義、特にファイル処理(須田)(未定稿)