如何在 SML 中编写多行字符串?

How to write multiline strings in SML?

如何编写跨多行的字符串?

我试过像许多其他语言一样在末尾使用续行符 \,但它似乎不起作用。以下:

val s = "line1\
line2";

生成错误:

/tmp/...:1: error: unexpected character l in \ ... \
/tmp/...:1: error: no matching quote found on this line

不使用任何续行符会产生类似的错误:

val s = "line1
line2";

多行字符串的正确写法是什么?

你也必须在下一行的开头加上反斜杠:

print "this is\
\ a string on\
\ 3 lines\n";

如果您正在使用 SML/NJ 并且您不太关心可移植性,则有一个鲜为人知的功能不仅可以为您提供多行字符串,还可以为您提供变量插值。 SML/NJ 支持可扩展的引用机制,这里有更详细的描述:https://www.smlnj.org/doc/quote.html

现在,为了解决您的问题,我们可以定义以下 引号解析器。我称它为 s 是为了与 Scala 的 s"..." 语法相提并论,这将在稍后变得更加清晰。

val s : string SMLofNJ.frag list -> string =
  let
    fun fold (SMLofNJ.QUOTE s, acc) = acc ^ s
      | fold (SMLofNJ.ANTIQUOTE s, acc) = acc ^ s
  in
    List.foldl fold ""
  end

请注意,它使用 SMLofNJ 结构来访问特定于编译器的数据类型和值(fragQUOTEANTIQUOTE)。

我们现在可以像这样使用上面的代码(确保您使用的是命令行选项 -Cparser.quotations=true):

$ sml -Cparser.quotations=true
- val a = "var";
val a = "var" : string
-
- val b = `this is a raw quotation using ^a`;
val b = [QUOTE "this is a raw quotation using ",ANTIQUOTE "var",QUOTE ""] :
  string SMLofNJ.frag list
-
- val c = s`this is an interpolated string: ^a`;
val c = "this is an interpolated string: var" : string
-
- print c;
this is an interpolated string: varval it = () : unit
-
- val d = s`this
… is
… a
… multiline string: ^a`;
val d = "this\nis\na\nmultiline string: var" : string
-
- print d;
this
is
a
multiline string: varval it = () : unit

如您所见,将引号与非常简单的自定义解析器(s 函数)结合使用,我们可以获得 SML/NJ.

中的多行内插字符串

在我的个人图书馆中,我以更结构化的方式定义了它:

structure Strings =
  struct
    structure Interpolated =
      struct
        local
          open SMLofNJ
        in
          (**
           * Support for multiline, interpolated strings.
           *
           * NB: requires SML/NJ quotations: sml -Cparser.quotations=true.
           *
           * ```sml
           * - open Strings.Interpolated;
           * - val v = "val";
           * val v = "val" : string
           * - val j = s`{
           * =   "key": "^v"
           * = }`;
           * val j = "{\n  \"key\": \"val\"\n}" : string
           * ```
           *)
          val s : string frag list -> string =
            let
              fun fold (QUOTE s, acc) = acc ^ s
                | fold (ANTIQUOTE s, acc) = acc ^ s
            in
              List.foldl fold ""
            end
        end
      end
  end