文法とか
https://github.com/carp-lang/Carp/blob/master/docs/LanguageGuide.md を見ながら文法の確認。
特殊形式は fn let do if while ref address set! the の9個だが(これで全部?)流石にそのままでは不便で、core/Macros.carpに色々ある。
例えば条件分岐だと cond when unless case があって、本体に一つの式しか取れないので when-do も定義されている。(unless-doはないのか?)
反復だと for foreach while-do forever-do
fib
たいして変わらないけど、一応フィボナッチ数もやってみる。
(defn fib [x] (cond (= x 0) 0 (= x 1) 1 (+ (fib (- x 1)) (fib (- x 2))))) (defn main [] (print* (fib 40) @"\n"))
time carp -x fib.carp
102334155 real 0m21.038s user 0m17.416s sys 0m0.480s
比較対象としてCommon Lisp版。処理系はSBCL 1.5.6
(defun fib (x) (cond ((= x 0) 0) ((= x 1) 1) (t (+ (fib (1- x)) (fib (- x 2)))))) (defun main () (pprint (fib 40)))
time ros run -l fib.lisp -e "(main)" -q
102334155 real 0m8.985s user 0m7.405s sys 0m0.109s
2倍位Carpが遅いがまあこんなもんなのかな? Carpの出力コードのfib関数はこんな感じ。
int fib(int x) { int _39; bool _8 = Int__EQ_(x, 0); if (_8) { int _11 = 0; _39 = _11; } else { int _37; bool _17 = Int__EQ_(x, 1); if (_17) { int _20 = 1; _37 = _20; } else { Lambda _23 = { .callback = fib, .env = NULL, .delete = NULL, .copy = NULL }; //Sym fib LookupRecursive int _27 = Int__MINUS_(x, 1); int _28 = _23.env ? ((int(*)(LambdaEnv, int))_23.callback)(_23.env, _27) : ((int(*)(int))_23.callback)(_27); Lambda _29 = { .callback = fib, .env = NULL, .delete = NULL, .copy = NULL }; //Sym fib LookupRecursive int _33 = Int__MINUS_(x, 2); int _34 = _29.env ? ((int(*)(LambdaEnv, int))_29.callback)(_29.env, _33) : ((int(*)(int))_29.callback)(_33); int _35 = Int__PLUS_(_28, _34); int _36 = _35; _37 = _36; } int _38 = _37; _39 = _38; } return _39; }
再帰呼び出しでちょっと遠回りしてるが、まだまだシンプルで素直に読める。
CFFI
出力がCなのでCFFIもサポート。 CarpからCのヘッダファイルを読み込む。
- system-include
- local-include
Carp上での型定義。
- register
- register-type
これやってて混乱するのはString型に感することで、Carpの String
はCの char *
に対応する。( const char *
か?)
それだけならいいが、Carpの文字列リテラルは &String
でありCの char * *
に対応する。
なので例えば、
(system-include "stdio.h") (register puts (Fn [String] Int)) (defn main [] (puts "Hello, world!"))
と書きたくなるんだけど、Carpのputsに渡しているのが文字列リテラルで型が &String
なのに対して、Cのputsは char *
でCarpの String
だから素直にいかない。
この辺について見てると、core/IO.carp
と core/carp_io.h
でprintln関数について、
void IO_println(String *s) { puts(*s); }
とやってCarpの &String
で受け取って、Cの関数でデリファレンスするという回りくどいことをするもの、らしい。
Carp側だと str
で型を合わせられる。
(system-include "stdio.h") (register puts (Fn [String] Int)) (defn main [] (puts (str "Hello, world!")))
carp -x cffi.carp
Hello, world! [RUNTIME ERROR] '"./out/Untitled"' exited with return value 14.
putsの返り値がそのままmainに返ってエラーがでてるけど、一応動作はする。