[MLton] Scanf
Vesa Karvonen
vesa.karvonen@cs.helsinki.fi
Sat, 27 Aug 2005 00:22:57 +0300
While on a train to Kajaani (>7 hours - argh) today, I wrote an experimental
Scanf implementation. It is still quite unpolished and I've only implemented
two conversion specifiers (D and G). I plan to improve it over the weekend,
but I thought that even the raw version might give something to think about
while bootstrapping MLton. ;-)
The syntax is similar to the alternative Printf:
scanf <source> (<conversion-specifier> <arg>*)* ($ | >>)
The <source> must be a pair of the type
('stream -> (char * 'stream) option) * 'stream
The $ terminator returns the product of the extracted elements and the
remaining stream, while >> passes the product to a function
(success continuation). For example,
- let open Scanf in scanf (fromString "3 - 3.1") D`" - "G $ end ;
val it = 3 & 3.1 & - : ((int,real) product,substring) product
and
- let open Scanf in scanf (fromString "3 - 3.1") D`" - "G >> (fn x => x) end ;
val it = 3 & 3.1 & - : ((int,real) product,substring) product
-Vesa Karvonen
fun id x = x
datatype ('a, 'b) product = & of 'a * 'b
infix &
(* this is just the same old alternative Printf *)
structure Printf =
struct
fun printf f = f id
fun newCvt_0_1 toS m f =
f (fn k => m (fn (g, s) => fn x1 => k (g, g (toS x1, s))))
fun newCvt_1_0 toS m a1 f =
f (fn k => m (fn (g, s) => k (g, g (toS a1, s))))
fun newCvt_1_1 toS m a1 f =
f (fn k => m (fn (g, s) => fn x1 => k (g, g (toS (a1, x1), s))))
val $ = fn m => m (List.app print o rev o (fn (_, s) => s)) (op::, [])
val $$ = fn m => m (fn (_, s) => concat (rev s)) (op::, [])
val ` = fn z => newCvt_1_0 id z
val C = fn z => newCvt_0_1 Char.toString z
val D = fn z => newCvt_0_1 Int.toString z
val G = fn z => newCvt_0_1 Real.toString z
val S = fn z => newCvt_0_1 id z
fun L cvt =
fn z =>
newCvt_0_1
let fun loop ss =
fn [] => "[]"
| [v] => concat ("["::rev ("]"::printf cvt$$v::ss))
| v::vs => loop (", "::printf cvt$$v::ss) vs
in loop [] end
z
end
structure Scanf =
struct
exception Scanf
fun scanf (g, s) f = f (g, s, fn v => v)
fun newCvt_0_1 scan (g, s, vs) f =
case scan (g, s) of
NONE => raise Scanf
| SOME (v, s) =>
f (g, s, let val vs = vs v in fn v => vs & v end)
fun newCvt_1_0 scan (g, s, vs) a1 f =
case scan (g, s, a1) of
NONE => raise Scanf
| SOME s =>
f (g, s, vs)
fun $ (g, s, vs) = vs s
fun >> (g, s, vs) f = f (vs s)
val ` = fn z => newCvt_1_0 (fn (g, s, s') =>
let
fun loop (s, s') =
case g s & Substring.getc s' of
SOME (c, s) & SOME (c', s') =>
if c = c' then
loop (s, s')
else
NONE
| _ & NONE => SOME s
| _ & SOME _ => NONE
in
loop (s, Substring.full s')
end)
z
val D = fn z => newCvt_0_1 (fn (g, s) => Int.scan StringCvt.DEC g s) z
val G = fn z => newCvt_0_1 (fn (g, s) => Real.scan g s) z
fun fromString s = (Substring.getc, Substring.full s)
end
val () =
let open Scanf in
scanf (fromString "An int 25 and a real 3.141\n")
`"An int "D`" and a real "G`"\n" >> end
let open Printf in
fn i & r & _ =>
printf `"Got an int "D`" and a real "G`".\n"$ i r end