我有一个函数返回像(char * int) list list这样的[[(#"D", 3)], [(#"F", 7)]],现在我想知道是否可以将其转换为字符串,以便我可以使用I/O并将其读取到另一个文件中?

最佳答案

首先,我假设您的意思是像[[(#"D", 3)], [(#"F", 7)]]这样的值(请注意额外的括号),因为SML需要在元组构造周围加上括号。 OCaml使用略有不同的语法,并且仅允许使用逗号(如a, b)来构造元组。我之所以这样说,是因为以下内容完全是针对标准ML的,而不适用于OCaml,因为我认为在OCaml中,您最好的选择是完全不同的方法,对此我不太了解(宏,即ocamlp4/5)。因此,我认为这只是一个错字,并且您对Standard ML感兴趣。

现在,不幸的是,标准ML中没有通用的toString函数。诸如此类的东西在语言和实现方面必须有某种特殊的支持,因为不可能用'a -> string类型编写函数。基本上,您必须为每种类型toString : t -> string编写自己的t

可以想象,这很快就变得很乏味。我花了一些时间研究选项(针对此选项以及其他样板函数,如compare : 't * 't -> order),论文“工作中的ML'er的泛型”(http://dl.acm.org/citation.cfm?id=1292547)中概述了一种非常有趣的技术,但它相当先进,我可以从来没有真正获得过要编译的代码(那说该论文非常有趣)。该论文中描述的完整泛型库位于MLton lib存储库(https://github.com/MLton/mltonlib/tree/master/com/ssh/generic/unstable)中。也许您会有更好的运气?

恕我直言,这是一种重量稍轻的方法,虽然功能不强,但更易于理解。在读完该论文并努力使其工作后,我写了这篇文章。这个想法是为toString函数(在这种情况下称为show)编写构建块,并将它们与您自己类型的其他函数组成。

structure Show =
   struct
      (* Show.t is the type of toString functions *)
      type 'a t = 'a -> string

      val int: int t = Int.toString

      val char: char t = Char.toString

      val list: 'a t -> 'a list t =
       fn show => fn xs => "[" ^ concat (ExtList.interleave (map show xs) ",") ^ "]"

      val pair: 'a t * 'b t -> ('a * 'b) t =
       fn (showa,showb) => fn (a,b) => "(" ^ showa a ^ "," ^ showb b ^ ")"

      (* ... *)
   end

由于您的类型实际上没有任何用户定义的数据类型,因此使用此结构编写toString函数非常容易:
local
   open Show
in
   val show : (char * int) list list -> string = list (list (pair (char, int)))
end

- show [[(#"D", 3)], [(#"F", 7)]] ;
val it = "[[(D,3)],[(F,7)]]" : string

我喜欢的是,组合函数的读取方式就像翻过来的类型一样。这是一种非常优雅的风格,我不能赞扬它,就像我从上面链接的泛型中获得的那样。
Show的其余代码(以及用于相等性比较的相关模块Eq)在此处:https://github.com/spacemanaki/lib.sml

10-08 06:17
查看更多