I'm trying to create a List reading a text file, for example I have a text file like this "1 5 12 9 2 6"
and I want to create a list like this [1,5,12,9,2,6]
using SML
You can divide this task into several sub-problems:
Reading a file into a string can be done with
type filepath = string
(* filepath -> string *)
fun readFile filePath =
let val fd = TextIO.openIn filePath
val s = TextIO.inputAll fd
val _ = TextIO.closeIn fd
in s end
See the TextIO
library.
Converting a string into a list of strings separated by whitespace can be done with
(* string -> string list *)
fun split s =
String.tokens Char.isSpace s
Converting a list of strings into a list of integers can be done with
(* 'a option list -> 'a list option *)
fun sequence (SOME x :: rest) = Option.map (fn xs => x :: xs) (sequence rest)
| sequence (NONE :: _) = NONE
| sequence [] = SOME []
fun convert ss = sequence (List.map Int.fromString ss)
Since any one string-to-integer conversion with Int.fromString
may fail and produce a NONE
, List.map Int.fromString
will produce an "int option list" rather than an "int list". This list of "int option" may be converted to an optional "int list", i.e., remove the SOME
of all the "int option", but if there's a single NONE
, the entire result is discarded and becomes NONE
. This gives the final type "int list option" (either NONE
or SOME [1,2,...]
).
See the Option.map
function which was useful for this kind of recursion.
Combining these,
(* filepath -> int list *)
fun readIntegers filePath =
convert (split (readFile filePath))
This approach does yield some potentially unwanted behavior:
readIntegers
throw an Io
exception~5
inside the file will be interpreted as negative five-5
will produce a failure (NONE
)123a
will produce the number 123 (Int.toString
is a bit too forgiving)You may want to address those.