GNU Guileは,主にGNUソフトウェアに組み込む機能拡張用言語の処理系として開発されている.たとえば,GNU EmacsやGNU makeに組み込み,設定ファイルをその拡張言語で記述することができる…はずなのだが,組込用としては未だほとんど利用されていない.
ただ,デフォルトの言語であるSchemeの処理系単体としては(今では)よくできており,最新の仕様(RnRSやSRFI)に沿っていることはもちろん,REPLコマンドは比較的使いやすい.今年1月にメジャーバージョンアップした3.0系列ではJITネイティブコードを生成するようになっている.
利用例は次の通り(サンプル記述は,手前味噌の不動点コンビネータ記事その他より).
$ guile --use-srfi=1,42
GNU Guile 3.0.4
Copyright (C) 1995-2020 Free Software Foundation, Inc.
Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.
Enter `,help' for help.
scheme@(guile-user)> (let ((n 5)) (list-ec (: y 1 (+ n 1)) (: x 1 y) (list x y)))
$1 = ((1 2) (1 3) (2 3) (1 4) (2 4) (3 4) (1 5) (2 5) (3 5) (4 5))
scheme@(guile-user)> (define (fix f) (f (lambda (x) ((fix f) x))))
scheme@(guile-user)> ((((fix (lambda (fib) (lambda (f1) (lambda (f2) (lambda (n)
(if (= n 0) f1 (((fib f2) (+ f1 f2)) (- n 1))))))))
0) 1) 40)
$2 = 102334155
scheme@(guile-user)> (map
(((fix (lambda (fib) (lambda (f1) (lambda (f2) (lambda (n)
(if (= n 0) f1 (((fib f2) (+ f1 f2)) (- n 1))))))))
0) 1)
(iota 6 0 10))
$3 = (0 55 6765 832040 102334155 12586269025)
ところで,SchemeはあくまでGuileのデフォルトの言語であり,他の言語にも対応している.それがECMAScriptとEmacs Lispであり,REPLを利用している間は,,language
または,L
で言語を切り替えることができる.
scheme@(guile-user)> ,L ecmascript
Happy hacking with ECMAScript! To switch back, type `,L scheme'.
ecmascript@(guile-user)> ,L elisp
Happy hacking with Emacs Lisp! To switch back, type `,L ecmascript'.
elisp@(guile-user)>
ECMAScriptに切り替え,上記とほぼ同じ内容を実行した例は次の通り.比較するとわかるが,Schemeで利用できる関数がECMAScriptでも利用できる.ただし,ECMAScript対応は開発が止まっており,ES3対応未完という状態らしい.
ecmascript@(guile-user)> function fix(f) {
return f(function(x) {
return fix(f)(x);
});
};
ecmascript@(guile-user)> (fix(function(fib) {
function(f1) {
function(f2) {
function(n) {
return n == 0 ? f1 : fib(f2)(f1+f2)(n-1);
};
};
};
})(0)(1)(40));
$1 = 102334155
ecmascript@(guile-user)> (map(fix(function(fib) { function(f1) { function(f2) { function(n) {
return n == 0 ? f1 : fib(f2)(f1+f2)(n-1);
}; }; }; })(0)(1), iota(6,0,10)));
$3 = (0 55 6765 832040 102334155 12586269025)
Emacs Lispに切り替え,上記とほぼ同じ内容を実行した例は次の通り.Schemeのレキシカルスコープは維持されており,Common Lispとほぼ同じ記述となる.なお,GNU Emacsのデフォルト設定であるダイナミックスコープを利用することも可能(本家GNU Emacsでも,最近はレキシカルスコープに切り替えることが可能).
elisp@(guile-user)> (defun fix (f)
(funcall f (lambda (x) (funcall (fix f) x))))
$1 = fix
elisp@(guile-user)> (funcall (funcall (funcall
(fix (lambda (fib) (lambda (f1) (lambda (f2) (lambda (n)
(if (= n 0) f1 (funcall (funcall (funcall fib f2) (+ f1 f2)) (- n 1))))))))
0) 1) 40)
$2 = 102334155
elisp@(guile-user)> (defun map (f l) (if (null l) '() (cons (funcall f (car l)) (map f (cdr l)))))
$3 = map
elisp@(guile-user)> (map (funcall (funcall
(fix (lambda (fib) (lambda (f1) (lambda (f2) (lambda (n)
(if (= n 0) f1 (funcall (funcall (funcall fib f2) (+ f1 f2)) (- n 1))))))))
0) 1) '(0 10 20 30 40 50))
$4 = (0 55 6765 832040 102334155 12586269025)
備考
更新履歴
- 2020-08-13:初版公開