Poly/ML はデフォルトで REPL で起動します。これは SML/NJ に似ています。さらに、実行時にコンパイラを簡単に呼び出すことができます。コンパイラはネイティブ コードを生成しeval
、LISP の場合と同様に ML 環境に追加しますが、それは静的に型付けされた実際のマシン コードであり、解釈されたものではありません。
この構造PolyML.Compiler
は、公式の SML 標準を超えて、それを行うためのさまざまな (比較的安定した) インターフェースを提供します。
Poly/ML 5.5 または 5.6 の実際の例を次に示します。
fun eval text =
let
fun print s = (TextIO.output (TextIO.stdOut, s); TextIO.flushOut TextIO.stdOut);
val line = ref 1;
val in_buffer = ref (String.explode text);
val out_buffer = ref ([]: string list);
fun output () = String.concat (rev (! out_buffer));
fun get () =
(case ! in_buffer of
[] => NONE
| c :: cs => (in_buffer := cs; if c = #"\n" then line := ! line + 1 else (); SOME c));
fun put s = out_buffer := s :: ! out_buffer;
fun put_message {message = msg1, hard, location = {startLine = line, ...}, context} =
(put (if hard then "Error: " else "Warning: ");
PolyML.prettyPrint (put, 76) msg1;
(case context of NONE => () | SOME msg2 => PolyML.prettyPrint (put, 76) msg2);
put ("Line " ^ Int.toString line ^ "\n"));
val parameters =
[PolyML.Compiler.CPOutStream put,
PolyML.Compiler.CPErrorMessageProc put_message,
PolyML.Compiler.CPLineNo (fn () => ! line)];
val _ =
(while not (List.null (! in_buffer)) do
PolyML.compiler (get, parameters) ())
handle exn =>
(put ("Exception- " ^ General.exnMessage exn ^ " raised");
print (output ()); raise exn);
in print (output ()) end;
これで、次のように通常の Poly/ML REPL でこれを呼び出すことができます。
> eval "1 + 1";
val it = 2: int
val it = (): unit
> eval "fun f 0 = 1 | f n = n * f (n - 1)";
val f = fn: int -> int
val it = (): unit
> eval "f 42";
val it = 1405006117752879898543142606244511569936384000000000: int
val it = (): unit
> f 42;
val it = 1405006117752879898543142606244511569936384000000000: int
これにより、静的に型付けされた SML の世界で LISP スタイルのメタプログラミングが可能になります。
PolyML.Compiler
構造体には、ランタイム コンパイラの呼び出しの動作を制御する追加のオプションがあることに注意してください。それについては、polyml メーリング リストで質問してください。