Sml 从溪流中读书

Sml 从溪流中读书,sml,Sml,我正试图从一个包含 test (注意空格)。目标是获得输出“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) en

我正试图从一个包含

   test 
(注意空格)。目标是获得输出“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\u rdr
有关,但我看不到一个好的定义方法,以便它既能取得进展,又能避免将被拒绝的字符丢弃到
skipWS
splitl
。欢迎发表一般性意见,但具体而言

  • 是否有一个预定义的
    (char,instream)读卡器
    具有这种行为
  • 不管它是否存在,我将如何编写一个(如果它确实存在,我希望被指向它的源代码)
  • 我是否应该使用完全不同的方法

  • 问题是,您的读者(微妙地)违反了读者的语义

    在这种情况下,
    StringCvt.skipWS
    假设,如果它调用
    stream\u rdr s
    ,并返回
    SOME(c,s')
    ,则原始的
    s
    保持不变

    也就是说,它可以尝试从字符源读取一个字符,直到它遇到一个非空白字符,然后只返回第一个不返回空白字符的字符。但是,在您的情况下,这是一个问题,因为调用
    stream\u rdr
    会修改
    s


    为了解决这个问题,我建议使用
    TextIO
    函数提供的字符读取器,而不是构建自己的字符读取器(
    stream\rdr
    )。

    我接受了Sebastian的建议,写了以下内容:

    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
    -
    
    该解决方案基于对内置程序的读取。如果您从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
     ...
    

    特别是,
    Bool
    的默认扫描器具有指导意义。如果您从Debian repos安装了
    mlton
    ,您可以在
    /usr/lib/mlton/sml/basis/general/bool.sml