从溪流中读取

时间:2014-12-07 16:56:20

标签: sml

我正在尝试从包含

的文件中读取一个单词
   test 

(注意空白)。目标是使输出“测试”。这是我到目前为止所得到的:

val test = TextIO.openIn "test.txt"

fun stream_rdr stream = let fun get NONE = NONE
                  | get (SOME c) = SOME (c, stream)
            in get (TextIO.input1 stream)
            end 

fun skip s = StringCvt.skipWS stream_rdr s

fun read_word stream = let val s = skip stream
               in case StringCvt.splitl Char.isAlpha stream_rdr s
               of ("", rest_s) => NONE
                | (w, rest_s) => SOME (w, rest_s)
               end 

问题在于它不起作用。

Standard ML of New Jersey v110.76 [built: Sun Jun 29 03:29:51 2014]
- use "Read.ml" ;;
[opening Read.ml]
[autoloading]
[library $SMLNJ-BASIS/basis.cm is stable]
[autoloading done]
val test = - : TextIO.instream
val stream_rdr = fn
  : TextIO.instream -> (TextIO.elem * TextIO.instream) option
val skip = fn : TextIO.instream -> TextIO.instream
val read_word = fn : TextIO.instream -> (string * TextIO.instream) option
val it = () : unit
- read_word test ;;
val it = SOME ("est",-) : (string * TextIO.instream) option
- 

我假设这与我定义stream_rdr的方式有关,但我看不到定义它的好方法,以便它既取得进展又避免将被拒绝的字符放到skipWSsplitl。一般评论欢迎,但具体而言......

  1. 是否有预定义的(char, instream) reader在某处出现此行为?
  2. 无论是否存在,我如何编写一个(如果确实存在,我会很感激被指向它的源代码)?
  3. 我应该使用完全不同的方法吗?

2 个答案:

答案 0 :(得分:1)

麻烦的是,你的读者(巧妙地)违反了读者的语义。

在这种情况下,StringCvt.skipWS会假设,如果它调用stream_rdr s,然后返回SOME (c, s'),则原始s仍未修改。

也就是说,它可以尝试从字符源中读取一个字符,直到它遇到非空白字符,然后简单地返回第一个不返回空白字符的字符。但是,这是一个问题,因为调用stream_rdr会修改s

要解决此问题,我建议您使用TextIO stream_rdr函数提供的字符阅读器,而不是构建自己的字符阅读器({{1} })。

答案 1 :(得分:1)

我最终接受了塞巴斯蒂安的建议并撰写了这篇文章:

val test = TextIO.openIn "test.txt"

fun scan_word reader state = let
    val s = StringCvt.skipWS reader state
in case StringCvt.splitl Char.isAlpha reader s of
       ("", ns) => NONE
     | (w, ns) => SOME (w, ns)
end

fun scan stream = TextIO.scanStream scan_word stream

它使用与之前相同的输入执行我想要的操作:

Standard ML of New Jersey v110.76 [built: Sun Jun 29 03:29:51 2014]
- [read.sml]
[autoloading]
[library $SMLNJ-BASIS/basis.cm is stable]
[autoloading done]
val test = - : TextIO.instream
val scan_word = fn : (char,'a) StringCvt.reader -> 'a -> (string * 'a) option
val scan = fn : TextIO.instream -> string option
val it = () : unit
- scan test ;;
val it = SOME "test" : string option
-

解决方案基于对内置Bool.scan的阅读。如果你从Debian repos安装了mlton,你会在/usr/lib/mlton/sml/basis/general/bool.sml找到来源。相关部分包括在下面:

 ...
  fun scan reader state =
     case reader state of
        NONE => NONE
      | SOME(c, state) =>
           case c of
              #"f" => (case Reader.reader4 reader state of
                          SOME((#"a", #"l", #"s", #"e"), state) =>
                             SOME(false, state)
                        | _ => NONE)
            | #"t" => (case Reader.reader3 reader state of
                          SOME((#"r", #"u", #"e"), state) =>
                             SOME(true, state)
                        | _ => NONE)
            | _ => NONE
 ...