J言語でFizzBuzzを作る


はじめに

プログラミング言語 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.ijs
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-43-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'は文字列なので、14などの数値も文字列に変えなければうまくいきません。

つまり動詞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:は、35というふうに、単に数値に置き換えることができます。

FizzBuzz=: 'FizzBuzz'&(":@]`(4{.[)`(4}.[)`[@.((0=3|])++:@(0=5|])))&>:&i.

ちなみに

J言語はif文やfor文も使えます。

FizzBuzz.ijs
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言語のエッセンスとクイックレファレンス そして講義、特にファイル処理(須田)(未定稿)