Я пытаюсь создать список, читающий текстовый файл, например, у меня есть текстовый файл, подобный этому "1 5 12 9 2 6", и я хочу создать список, подобный этому [1,5,12,9,2,6], используя SML
"1 5 12 9 2 6"
[1,5,12,9,2,6]
Вы можете разделить эту задачу на несколько подзадач:
Чтение файла в строку можно выполнить с помощью
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
См. the TextIO библиотека .
TextIO
Преобразование строки в список строк, разделенных пробелами, можно выполнить с помощью
(* string -> string list *) fun split s = String.tokens Char.isSpace s
См. the String.tokens функция .
String.tokens
Преобразование списка строк в список целых чисел можно выполнить с помощью
(* '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)
, так как любая строка является целым числом преобразование с Int.fromString может завершиться с ошибкой, и NONE, List.map Int.fromString создаст "int option list", а не "int list". Этот список «int option» может быть преобразован в необязательный «int list», т. Е. Удалить SOME из всех «int option», но если существует один NONE, весь результат отбрасывается и становится NONE. Это дает окончательный тип «int list option» (NONE или SOME [1,2,...]).
Int.fromString
NONE
List.map Int.fromString
SOME
SOME [1,2,...]
См. функцию Option.map , которая была полезна для такого рода рекурсии.
Option.map
Комбинируя их,
(* filepath -> int list *) fun readIntegers filePath = convert (split (readFile filePath))
Этот подход приводит к потенциально нежелательному поведению:
readIntegers
Io
~5
-5
123a
Int.toString
Возможно, вы захотите обратиться к ним.