Poly/ML starts up with REPL by default, which is similar to SML/NJ. Moreover, you can invoke the compiler easily at runtime: it will produce native code for you and add it to the ML environment in the manner of eval
in LISP, but it is statically typed and real machine code, not interpreted one.
The structure PolyML.Compiler
provides various (relatively stable) interfaces to do that, beyond the official SML standard.
Here is a worked example for Poly/ML 5.5 or 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;
Now we can invoke this at the normal Poly/ML REPL like this:
> 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
This gives you LISP-style meta-programming in the statically typed world of SML.
Note that structure PolyML.Compiler
has further options to control the behaviour of the runtime compiler invocation. Better ask at the polyml mailing list about it.