xs-lang
右から左に値をスタックに積んで評価する、Forthの逆版ような動作 xs は eXtra Small の意味らしく言語仕様が小さいとのこと
PoC提示のため言語で実装も小さい。
個人的感想
Forthのようなスタックベース、ポイントレススタイルの言語で、コード中に出現したワードをForthとは逆に右から左にスタックに積むような言語を設計したとき、 どのような文法・言語仕様が最適なのか?というのを確認するために実装された言語のように感じる。
サンプルコード
code:factrial.xs
fac:(prod 1+til);
code:fibonnaci.xs
fib:(n:(neg 1)+;0@n do(2 enlist 1@x sum x~)0 1); code:euclid_gcd.xs
gcd:{([xy]):..;if y==0(x)(y gcd x mod y)};
チュートリアル
xsはすべての操作が右から左に解析される連結型(またはスタックベース)の言語
code:add.xs
xs> 2+5 ! スタック型言語なので演算子の優先順位はない
0: 7
+ 演算子が infix 方式で使われているが…?
xs では、左隣の値の位置と入れ替わる特別な演算子を定義できる
内部的には、インタープリターは + 2 5 を実行している
演算子を infix 形式ではなく通常の関数として使うには . 演算子を追加する
code:add_fn.xs
xs> +. 3 2
0: 5
. 演算子は左側の値を引用符を付けた `+ としてスタックに積む
引用符を付けた識別子は空白を含めることができない文字列のようなものと認識できる
よってスタックは
code:+..xs
. `+ 3 2
のようになる。
ここで .演算子は、いわゆる apply() のように振る舞う。この場合 apply("+", 3, 2)
これが実行され、最終的に5がスタックの先頭になる。
関数定義(関数リテラルを識別子に代入しているだけ)
code:def.xs
xs> mul2:(2*) ! 2倍する関数
xs> mul2 5
0: 10
変数定義と代入
code:var.xs
xs> x:3 ! : で識別子に値を代入する
xs> mul2 x
0: 6
参照
code:deref.xs
xs> x:5
xs> x. ! .付与で deref
0:5
関数リテラルの実行
code:lambda.xs
xs> (2*). 5 ! . で無名関数的に実行可能
0: 10
ドット演算子について詳しく
左側の値によって動作が異なる
関数の場合は apply
変数の場合は、その値を deref してスタックに積む
code:dot.xs
xs> x:5
xs> x.
0:5
. 演算子に . を被せることも可能
code:dot.xs
xs> x:5
xs> ..x ! x が積まれたあとに . が左隣の . を呼び出し `x
0:5
関数リテラルがコード上に現れたとき、 . 演算子がないと単にスタックに積まれて実行されない。
これが.が必要な理由
非ポイントレススタイルの関数定義
code:not-pointless.xs
xs> (x:; 2*x). 5 ! 2*x x:5
0: 10
セミコロンで記述を分割できる
code:semicolon.xs
xs> (2+2; 3+) ! 3 + 2 + 2 と同じ. ; で記述が分割されているので 3+ が先に積まれるわけではない
0: 7
演算子の定義
code:defop1.xs
xs> add:{y:x; x+y} ! {..}で囲む
xs> 3 add 4
0: 7
しかし、この定義では変数利用時に以下のエラーが発生する
code:defop2.xs
xs> x:3; x add 4
(Failure "+ applied on invalid types")
この理由は、変数x が add に対して引用符付き変数 `x として渡されてしまうため。
よって、変数x を add にわたす前に deref する必要がある
code:defop3.xs
xs> add:{y:x:..; x+y} ! .. はドット演算子が2個並んでいるだけで .. で一塊ではないことに注意
xs> x:3; x add 4
0: 7
.. はドット演算子にドット演算子を適用している。
最初のステートメントで、変数xをスタック上の一番最初の値(.によって参照解除された後)にバインドし、次に変数yを二番目の値にバインドしていることに注目してください。 これは、多くの関数の最初の行で最初に変数を設定するため、xsでは一般的な操作であることがわかります(多くの場合、明示的な変数を使用する方が、ポイントを使わないスタイルよりも明確です):