OCaml:如何以pythonic方式构造格式化字符串?

Nul*_*ter 2 python ocaml

所有这些都从一个简单的想法开始:如何在ocaml中编写python样式的格式化字符串.

pythoners可以初始化一个字符串:

str = "this var: %s" % this_var
str2 = "this: %s; that: %s" % (this_var, that_var)
Run Code Online (Sandbox Code Playgroud)

但ocaml的格式化字符串代码为:

let str = Printf.sprintf "this var: %s" this_var
let str2 = Printf.sprintf "this: %s; that: %s" this_var that_var
Run Code Online (Sandbox Code Playgroud)

我相信我可以做ochl字符串格式化代码python-like首先,我定义了一个函数如下:

let (%) s x = Printf.sprintf s x
Run Code Online (Sandbox Code Playgroud)

那么,我可以直接写作:

let str = "this: %s" % "sth"
Run Code Online (Sandbox Code Playgroud)

但是简单的函数不能处理两个或多个变量的更复杂的情况.所以我想编写一个复杂的函数来使它完美地模拟python方式.我写的如下:

let (%) s li = 
  let split_list = Str.full_split (regexp "%[a-z]") s in
  let rec fmt result_str s_list x_list = match s_list with
    | [] -> result_str
    | shd::stl -> match shd with
       | Text t ->  fmt (result_str^t) stl x_list
       | Delim d -> match x_list with
          | [] -> fmt result_str stl []
          | xhd::xtl -> fmt (result_str^(Printf.sprintf d xhd)) stl xtl
  in 
  fmt "" split_list li
Run Code Online (Sandbox Code Playgroud)

但是函数只是无法工作,因为类型错误和ocaml的列表不能包含多种类型.如果你写得像: "name: %s; age: %d" % ["John"; 20]ocaml编译器世界嘲笑代码并告诉你一些类型错误.

显然,我必须使用Tuple来替换List.但我只是不知道如何尾递归一个可变长度的元组.

任何建议都受到欢迎.我确实有两个问题.

  1. 如何编写pythonic ocaml代码来格式化字符串.
  2. 如果Ocaml无法动态生成某些字符串作为format6 str并将其传递给sprintf?代码:

    在printf.sprintf的"你好"中让s ="%s"

    将生成错误信息:

    错误:此表达式具有类型字符串,但表达式需要类型('a - >'b,unit,string)format =('a - >'b,unit,string,string,string,string)format6

new*_*cct 5

(1)我认为没有比Printf.sprintf直接使用更好的方法.我的意思是,你可以扩展你已经提出的东西:

let (%) = Printf.sprintf
let str3 = ("this: %s; that: %s; other: %s" % this_var) that_var other_var
Run Code Online (Sandbox Code Playgroud)

这是有效的,但由于优先权所必需的括号,因此很难看.

(2)在运行时生成格式字符串非常困难,因为格式字符串在编译时被解析.它们可能看起来像字符串文字,但它们实际上是一种不同的类型,这是"格式6".(它根据推断类型确定您是否需要字符串或格式字符串)事实上,格式字符串的确切类型取决于格式中的占位符; 这是它能够键入检查格式参数的数量和类型的唯一方法.最好不要弄乱格式字符串,因为它们与类型系统密切相关.


Pat*_*atJ 5

如果您的运算符以#字符开头,这实际上是可行的,因为该字符的优先级高于函数应用程序。

let (#%) = Printf.sprintf;;
val ( #% ) : ('a, unit, string) format -> 'a = <fun>
"Hello %s! Today's number is %d." #% "Pat" 42;;
- : string = "Hello Pat! Today's number is 42."
Run Code Online (Sandbox Code Playgroud)