创建一个使用 SML 读取文件的列表

Create a list reading a file with SML

我正在尝试创建一个读取文本文件的列表,例如,我有一个这样的文本文件 "1 5 12 9 2 6",我想使用 [=14] 创建一个这样的列表 [1,5,12,9,2,6] =]SML

你可以把这个任务分成几个子问题:

  1. 可以使用

    将文件读入字符串
    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 library

  2. 可以使用

    将字符串转换为由空格分隔的字符串列表
    (* string -> string list *)
    fun split s =
        String.tokens Char.isSpace s
    

    参见 the String.tokens function

  3. 可以使用

    将字符串列表转换为整数列表
    (* '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",即删除所有 "int option" 中的 SOME,但如果只有一个 NONE,则整个结果被丢弃并变为 NONE。这给出了最终类型 "int list option"(NONESOME [1,2,...])。

    参见 the Option.map function 对这种递归很有用。

  4. 结合这些,

    (* filepath -> int list *)
    fun readIntegers filePath =
        convert (split (readFile filePath))
    

这种方法确实会产生一些可能不需要的行为:

  • 文件系统错误会使 readIntegers 抛出 Io 异常
  • 文件里面的字符串~5会被解释为负五
  • 字符串-5将产生失败(NONE)
  • 字符串 123a 将产生数字 123(Int.toString 有点太宽容了)

您可能想要解决这些问题。