1.はじめに
一文字言語とは、その名前が1文字である言語のことです。
有名なものだとC言語、その後継を目指すD言語、Dはdeathの頭文字でなんか縁起が悪いからE言語などがあります。
作るならO言語か……
— フクダ (@hukuda222) September 4, 2016
これは豆知識だけど、A言語からZ言語の中でO言語だけ無いらしい
— xxkiritoxx (@unko08658932) October 18, 2017
現在国内ではこの一文字言語の中でO言語のみ存在しないという通説が信じられていますが、
だがしかし、これを見てください
The O Language — The O Language 2.0 documentation
https://o.readthedocs.io
あ っ た
ツイッターなどを検索していると、古く不正確な情報を真に受けていまだにO言語が存在しないことを信じている人が一定数存在します。彼らには悪いのですがこの事実を世に知らしめるためこの記事ではO言語を紹介していきます。
2.O言語の詳細と導入 ~これで君もOerだ!!!~
The O Language is an esoteric programming language used for code-golf.(https://o.readthedocs.io より)
O言語はコードゴルフ、つまりある問題を如何に短いコードで解くかの競争のために生まれてしまった言語です。
Hello Worldはこう書かれます。
"Hello!World!!!"o
"Hello!World!!!"をスタックにpushし、oでそれをpopし出力するプログラムです。
O revolves around one stack in which you can push and pop values to and from. Here are some basic rules for writing O code.
Oにはスタックの概念があり、そこに上からオブジェクトをpush(追加)し、pop(引き出し)しながらプログラムを進めていきます。
ところでO言語のインタプリタはコードがなくなった段階でスタックにあるものを全て(何と下から!)出力するため、実は出力oは必要ないです。つまり
"Hello!World!!!"
もHello!World!!!を出力します。
"Hello!World!!!
も実は同じ動きをします。
これはプログラムが終了まで読み込まれた段階で""
が閉じていないならば、自動的に"を閉じてくれるためです
ここまでで何となく察しただろうがOの命令はほとんどが1文字で完結します。
変数やフロー制御もあるがその辺りは後々紹介します。
gitに乗っているサンプルコードだと
H,;]*
は入力の階乗
0J;1Kpj{K:VJ+:KpV:J;}d
はフィボナッチ数列を計算し出力します。
興味を持ってもらえたところで導入方法を紹介します。
Oのインタプリタを導入するには
https://o.readthedocs.io/en/latest/getting-started.html#getting-the-interpreter
を参照して欲しい。
git clone https://github.com/phase/o && cd o
make all
./o
をすればいい。
またはオンラインで動くIDEがある
http://o-lang.herokuapp.com
3.O言語超入門編
i
は入力をstringとして読み込みpushします。
j
は入力をintegerとして読み込みpushsします。
o
はスタックから1つオブジェクトをpopし出力します。
p
はスタックから1つオブジェクトをpopし出力し、flashをします。
0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F
のそれぞれはそれぞれの対応するintegerをpushする。ここで注意すべきは、
1234
は1,2,3,4を順番にpushsすることです。(1234、つまりせんにひゃくさんじゅうよんを整数でスタックするのには別の方法を用います。)
q,Q
は入力が数字なら数字を、そうでないならstringをpushします。便利。
""
は囲まれた文字を文字列としてpushします
'
は単体では次の一文字をstringとしてpushします。
""
節の途中での'
は、""
のマクロとして働きます。
>>> "hello'madam"oo
madamhello
+ - * / %
はスタックから2つ要素をpopし、計算の結果をpushします
>>> 12+o
3
>>> 75-o
2
>>> 85*o
40
>>> 42/o
2
>>> 53/
1.666667
4.いかがでしたか?
O言語はコードゴルフのための言語で四則演算とかができることがわかりましたね! これで公式サイトに載っていた内容は全てです。お疲れ様でした。 次回はKaGuiさんの記事とSilviaseさんの記事だそうです。よろしければそっちも見てね☆5.付録
https://github.com/phase/o/blob/master/commands.md
を見るとなんか公式サイトに載ってない命令がめっちゃ載ってますね。
このセクションの存在に気づいてしまったそこの不幸なあなたのためにそれぞれ紹介していきましょう。
ただし上記ファイルに乗っている説明はかなりあっさりなので100%機能を網羅していない点に気をつけてください。公式リファレンスがないのが悪いんだよ
"
String parsing
説明:""
で囲まれた文字列をpushする
>>> "oisu~"
output:oisu~
stack:[oisu~]
#
String to number
説明:1つpopし、それがstringなら数値型にしてpushする
>>> "100"#
output:100
stack:[100]
$
Take object from lower stack up
Arrayの宣言時に、1つ上のスタックから値をpopし、今のスタック(つまりArrayの内部である)にpushする?
説明:
>>> 12345[$$]
output:123[5,4]
stack:[[5,4],3,2,1]
%
Modulous
説明:2つpopし(2つめ)%(1つめ)を計算しpushする。
>>> 53%
output:2
stack:[2]
&
Get element from array
説明:Arrayをpopし、最下の要素を取り出し、Arrayをpushし取り出した要素をpushする
>>> [12345]&
output:[1,2,3,4]5
stack:[5,[1,2,3,4]]
'
Character literal
説明:単体で使用した場合、次の一文字をstringとしてpushする。
>>> 'a
output:a
stack:[a]
(
Decrement
説明:pushした数値から1引いた答えをpushする
>>> 5(
output:4
stack:[4]
)
Increment
説明:pushした数値から1足した答えをpushする
>>> 5)
output:6
stack:[6]
*
Multiplication
説明:2つpopした数値の積を計算する。または文字列の繰り返し?
>>> 23*
output:6
stack:[6]
>>> "oisu~"3*
output:oisu~oisu~oisu~
stack:[oisu~oisu~oisu~]
+
Addition
説明:2つpopした数値の和を計算する。または文字列の結合?
1つめにpopしたものが数値または文字列なら、2つめがArrayでも全要素に対して計算する。
1つめにpopしたものがArrayなら要素の和を計算する。(2つめをpopしない)
>>> 12+
output:3
stack:[3]
>>> "Hello!!'World!!!"+
output:Hello!!World!!!
stack:[Hello!!World!!!]
>>> [5,]+
output:15
stack[15]
,
Range
説明:popした数値から0までをまでを1刻みでpushする。
>>> "10"#,
output:109876543210
stack:[0,1,2,3,4,5,6,7,8,9,10]
-
Subtraction
説明:2つpopした数値の差(2つめ)-(1つめ)を計算する。または(2つめ)の文字列から(1つめ)の部分文字列を取り除く?
1つめにpopしたオブジェクトが数値なら、2つめがArrayでも全要素に対して計算する。
1つめがArrayなら、2つめをpopせずそれぞれの要素を偶数インデックスはそのまま、奇数インデックスは符号反転して和を計算する。
>>> 53-
output:
stack:
>>> "oisu~""is"-
output ou~
stack:[ou~]
>>> [A,]2-
output:[8,7,6,5,4,3,2,1,0,-1,-2]
stack:[[8,7,6,5,4,3,2,1,0,-1,-2]]
.
Clone the top of the stack
説明:1つpopし、同じオブジェクトを2つpushする
>>> "Hello!".
output:Hello!Hello!
stack:[Hello!,Hello!]
/
Division
説明:popした2つの数値の商(2つめ)/(1つめ)を計算しpushする。または文字列のsplit?
1つめにpopしたオブジェクトが数値、文字列なら、2つめがArrayでも全要素に対して計算する。
1つめがArrayなら、2つめをpopせず偶数インデックスの積/奇数インデックスの積を計算する。
>>> 53/
output:1.666667
stack:[1.666667]
>>> "Ha? Mango is Delicious"" "/
output:HA?MangoisDelicious
stack:[Delicious,is,Mango,"Ha?"]
>>> "Ha? Mango is Delicious"""/
output:Ha? Mango is Delicious
stack:[s,u,o,i,c,i,l,e,D, ,s,i, ,o,g,n,a,M, ,?,a,H]
0
Push 0
説明:0をpushします
>>> 0
output:0
stack:[0]
1
Push 1
説明:1をpushします
>>> 1
output:1
stack:[1]
2
Push 2
説明:2をpushします
>>> 2
output:2
stack:[2]
3
Push 3
説明:3をpushします
>>> 3
output:3
stack:[3]
4
Push 4
説明:4をpushします
>>> 4
output:4
stack:[4]
5
Push 5
説明:5をpushします
>>> 5
output:5
stack:[5]
6
Push 6
説明:6をpushします
>>> 6
output:6
stack:[6]
7
Push 7
説明:7をpushします
>>> 7
output:7
stack:[7]
8
Push 8
説明:8をpushします
>>> 8
output:8
stack:[8]
9
Push 9
説明:9をpushします
>>> 9
output:9
stack:[9]
:
Assign to variable
説明:1つpopし、次の一文字をそのマクロとします。その後、popしたものをpushします
>>> :V;"oisu~"V*
output:oisu~oisu~oisu~oisu~oisu~
stack:[oisu~oisu~oisu~oisu~oisu~]
;
Pop top value of stack
説明:スタックの最上の要素をpopします。
>>> 12345;
output:1234
stack:[4,3,2,1]
<
Less than
説明:popした数値2つを比較し、(2つめ)<(1つめ)なら1を、そうでないなら0をpushします。
または1つめの文字列が2つめの文字列を部分文字列としてもつかどうか?
1つめにpopしたものが数値または文字列なら、2つめがArrayでも全要素に対して計算する?
>>> 12<
output:1
stack:[1]
>>> "Mango""ngo"<
output:1
stack[1]
>>> "Mango""nngo"<
output:0
stack[0]
=
Equal to
説明:popした2つの数値、文字列、コードブロックを比較し、等しいなら1を、そうでないなら0をpushする
>>> 11=
output:1
stack:[1]
>>> '11=
output:0
stack[0]
>
Greater than
説明:popした数値2つを比較し、(2つめ)<(1つめ)なら1を、そうでないなら0をpushします。
または2つめの文字列が1つめの文字列を部分文字列としてもつかどうか?
1つめにpopしたものが数値または文字列なら、2つめがArrayでも全要素に対して計算する?
>>> 13<
output:1
stack:[0]
?
If????
説明:3つpopし、(3つめ)が0なら1つめのコードブロックを。そうでないなら2つめのコードブロックを実行します
>>> 01>{"true"}{"false"}?
output:false
stack:false
@
Rotate top three items on stack
説明:スタックの先頭3要素を回転させます。(例を参照)
>>> 1234@
output:1342
stack:[2,4,3,1]
A
Push 10
説明:10をpushします
>>> A
output:10
stack:[10]
B
Push 11
説明:11をpushします
>>> B
output:11
stack:[11]
C
Push 12
説明:12をpushします
>>> C
output:12
stack:[12]
D
Push 13
説明:13をpushします
>>>
output:13
stack:[13]
E
Push 14
説明:14をpushします
>>> 14
output:14
stack:[14]
F
Push 15
説明:15をpushします
>>> F
output:15
stack:[15]
G
Push alphabet
説明:"abcdefghijklmnopqrstuvwxyz"をpushします。これいる?
>>> G
output:abcdefghijklmnopqrstuvwxyz
stack:[abcdefghijklmnopqrstuvwxyz]
H
Macro for
[Q
説明:[Qのマクロ。
>>> H]
input:po
output:[po]
stack:[[po]]
I
Macro for
[i
説明:[iのマクロ。
>>> I]
input:po
output:[po]
stack:[[po]]
J
Magic var
説明:初めて読んだときは:J
のマクロとして働き、2度目以降は単にJの値をpushする
>>> AJ2J
output:10210
stack:[10,2,10]
K
Magic var
説明:初めて読んだときは:K
のマクロとして働き、2度目以降は単にKの値をpushする
>>> AK2K
output:10210
stack:[10,2,10]
L
Lambda (Push next character as a standalone CodeBlock:
Lo
->{o}
)
説明:次の1文字を単体でコードブロックにしてpushする
>>> "Mango"Lo
output:Mango{o}
stack:[{o},Hello]
M
Macro for
[i~
説明:[i~
のマクロ
>>> M]
input:12+
output:[3]
stack:[[3]]
N
Push blank CodeBlock
説明:{}
(空のコードブロック)をpushする
>>> N
output:{}
stack:[{}]
Q
Input var
説明:入力を受け付ける。数値なら数値型、そうでないなら文字列型としてpushする
>>> QQ+
input:1
2
output:2
stack:[2]
S
Blank String
説明:""
のマクロ。
>>> "Ha? Mango is Delicious"S/
output:Ha? Mango is Delicious
stack:[s,u,o,i,c,i,l,e,D, ,s,i, ,o,g,n,a,M, ,?,a,H]
T
String with space
" "
説明:" "
のマクロ。
>>> "Ha? Mango is Delicious"T/
output:Ha?MangoisDelicious
stack:[Delicious,is,Mango,Ha?]
U
Newline string
"\n"
説明:"\n"のマクロ。改行文字。
>>> "Ha? Mango "U+"is Delicious"+
output:Ha? Mango
is Delicious
stack:[Ha? Mango \nis Delicious]
V
Commonly used for variables
説明:O言語でもっとも一般的な変数名
>>> A:VVVV
output:10101010
stack:[10,10,10,10]
W
Push 32
説明:32をpushする
>>> W
output:32
stack:[32]
X
Push 33
説明:33をpushする。
>>> W
output:33
stack:[33]
Y
Push 34
説明:34をpushする
>>> Y
output:34
stack:[34]
Z
Push 35
説明:35をpushする
>>> Z
output:35
stack:[35]
[
Start array
説明:[]
で囲まれたところはArrayになる。[]
内のコードを別のスタック上で実行し、結果のスタックをArrayとしてpushする?
>>> AK[K,;;]
output:10[10,9,8,7,6,5,4,3,2]
stack:[[10,9,8,7,6,5,4,3,2],10]
\
Swap two objects on stack
説明:スタックの先頭2要素を入れ替える。
>>> A,\
output:109876543201
stack:[1,0,2,3,4,5,6,7,8,9,10]
]
End array
説明:Arrayの宣言の終了。ここまで読んだらスタックの内容をArrayにしてpushする。
>>> AK[K,;;]
output:10[10,9,8,7,6,5,4,3,2]
stack:[[10,9,8,7,6,5,4,3,2],10]
^
Power?
説明:2つ数値をpopして、(2つめ)^(1つめ)を計算してpushする
1つめにpopしたものが数値なら、2つめがArrayでも全要素に対して計算する。
1つめにpopしたものがArrayなら最下要素の(下から2つめ^(下から3つめ^(.......)))計算する?
>>> 33^
output:27
stack:[27]
>>> [334]3^
output:[27,27,64]
stack:[[27,27,64]]
[234]^
output:2417851639229258349412352
stack:[2417851639229258349412352]
note:2^(3^4)
_
Negate
説明:popした数値の符号を逆転したものをpushする
>>> 5_
output:-5
stack:[-5]
`
Reverse String
説明:popしたstringを逆転させたものをpush
>>> "Ha? Mango is Delicious"`
output:suoicileD si ognaM ?aH
stack:[suoicileD si ognaM ?aH]
c
Compress int to string
説明:数値をstringに圧縮する?詳細不明
d
For loop
説明:2つpopする。(1つめ)のコードブロックを(2つめ)の回数だけ繰り返す。
または2つめがArrayやstringならforeachとして働く?
>>> 9{"Hello"oUo}d
output:Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
stack:[]
>>> "oisu~"{np}d
[334]{np}d
output:o
i
s
u
~
3
3
4
stack:[]
e
Is even? / String length
説明:1つpopする。popしたものがstring、Arrayの場合、string、Arrayをpushし、長さをpushする。
数値をpopした場合、0なら1、それ以外なら0をpushする。
>>> "Hello"e
output:Hello5
stack:[5,Hello]
>>> 0e
output:1
stack:[1]
i
String input
説明:文字列を標準入力から受け取り、stringとしてpushする。
>>> i
input:oisu~
output:oisu~
stack:[oisu~]
j
Number input
説明:文字列を読み取り、数値としてpushする。できない場合はエラーを出力し停止。
>>> j
input:10
output:10
stack:[10]
l
Push length of stack
説明:今のスタックの長さをpushする
>>> 12345[12345]{12345}l
output:12345[1,2,3,4,5]{12345}7
stack:[7,{12345},[1,2,3,4,5],5,4,3,2,1]
m
Math functions
説明:次の一文字と合わせて数学関数を実行するらしい。謎
>>> 1ms
output:0.841471
stack:[0.841471]
note:sin(1)~=0.841471
>>> 1ma
output:0.540302
stack:[0.540302]
note:cos(1)~=0.540302
>>> 1mt
output:1.557408
stack:[1.557408]
note:tan(1)~=1.557408
>>> mp
output:3.141593
stack:[3.141593]
>>>
>>> ml
output:299792458
stack:[299792458]
note:光速のことか?
他にも色々あったにはあった
ソースコードを見る限りでは、
q sqrt
[ floor
] ceil
s sin
S asin
c cos
C acos
t tan
T atan
d mdst:sqrt(x^2+y^2)
r mrng:range x:y
p pi
e e
l light speed
n
Used in for loops
説明:d
中に呼ぶと、ループ回数をpushする。
>>> 9{noUo}d
output:0
1
2
3
4
5
6
7
8
stack:[]
o
Print object
説明:1つpopして標準出力する。
>>> 9{noUo}d
output:0
1
2
3
4
5
6
7
8
stack:[]
p
Print object with new line
説明:1つオブジェクトをpopし、標準出力に出力後flashする。
>>> 9{np}d
output:0
1
2
3
4
5
6
7
8
stack:[]
q
Push input as string/number
説明:stringまたは数値型として入力をpushする
>>> q
input:10
output:10
stack:[10]
s
Split string into char array
説明:stringをpopし、charのArrayとしてpopする
>>> "Hello"s
output:[H,e,l,l,o]
stack:[[H,e,l,l,o]]
w
While Loop
説明:2つpopする。(1つめ)のコードブロックを(2つめ)が0でない限り繰り返す?2つめをpushする?謎
>>> 3_Kp{K):K}{Kp}w
output:-3
-2
-1
{K):K}
stack:[{K):K}]
{
Start CodeBlock
説明:コードブロックの開始
>>> {"Hello"}
output:{"Hello"}
stack:[{"Hello"}]
>>> {"Hello"}{o"World"o}+
output:{"Hello"o"World"o}
Stack:[{"Hello"o"World"o}]
}
End CodeBlock
説明:コードブロックを閉じる
>>> {"Goodbye"}
output:{"Goodbye"}
stack:[{"Goodbye"}]
>>> {"Oisu~"}3*
output:{"Oisu~""Oisu~""Oisu~"}
stack:[{"Oisu~""Oisu~""Oisu~"}]
note:扱いは文字列に近いか?
~
Eval
説明:コードブロックまたはstringの式を実行
>>> "334"~{"334"}~
output:334334
stack:[334,4,3,3]
6. 終わりに
なんか色々実行してたらよくわからない機能を発見して追記が3回ぐらいあったんですがそれ以降はもう疲れたので書いていません。
自分で試してレッツエンジョイO言語ライフ!
じゃあ私C#書くので✋