OCaml:如何以Python方式构造格式化字符串?
所有这些都始于一个简单的想法:如何在 ocaml 中编写 python 风格的格式化字符串。
pythoners可以将字符串初始化为:
str = "this var: %s" % this_var
str2 = "this: %s; that: %s" % (this_var, that_var)
但是ocaml的格式化字符串代码为:
let str = Printf.sprintf "this var: %s" this_var
let str2 = Printf.sprintf "this: %s; that: %s" this_var that_var
我相信我可以做一些事情来使ocaml字符串格式化代码像python一样 首先,我定义了一个函数如下:
let (%) s x = Printf.sprintf s x
然后,我可以直接写为:
let str = "this: %s" % "sth"
但简单的函数无法处理作为两个或多个变量的更复杂的情况。 所以我想写一个稍微复杂的函数来让它完美地模拟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
但是该函数无法工作,因为类型错误以及 ocaml 的列表不能包含多种类型。 如果你写这样的东西: "name: %s;age: %d" % ["John"; 20]
ocaml 编译器世界嘲笑代码并告诉你一些类型错误。
显然,我必须用Tuple来代替List。但我只是不知道如何尾递归可变长度元组。
欢迎任何建议。我确实有两个问题。
- 如何编写 pythonic ocaml 代码来格式化字符串。
如果Ocaml无法动态生成某些字符串作为format6 str并且 将其传递给 sprintf 吗?代码:
让 s = "%s" in Printf.sprintf s "hello"
将生成错误信息:
<块引用>错误:此表达式的类型为字符串 但需要一个表达式类型 ('a -> 'b, 单位, 字符串) 格式= ('a -> 'b,单位,字符串,字符串,字符串,字符串)格式6
All of these start from a simple idea: How to write python-style formatted string in ocaml.
pythoners could init a string as:
str = "this var: %s" % this_var
str2 = "this: %s; that: %s" % (this_var, that_var)
but ocaml's formatted string code as :
let str = Printf.sprintf "this var: %s" this_var
let str2 = Printf.sprintf "this: %s; that: %s" this_var that_var
I believed I can do sth to make the ocaml string formating code python-like
At first, I defined a function as below:
let (%) s x = Printf.sprintf s x
then, I can write directly as:
let str = "this: %s" % "sth"
but the simple function cannot handle more complex situations as two or more variables.
so I wanted to write a little complex function to make it perfectly simulate the python way.
I wrote it as below :
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
But the function just CANNOT work, because the type error and also ocaml's list cannot contains multiple types.
if you write sth like: "name: %s; age: %d" % ["John"; 20]
the ocaml compiler world laugh at the code and tell you some type ERROR.
Obviously, I must use Tuple to replace List. but I just do NOT konw how to tail-recursive a variable-length tuple.
any suggestion is welcomed. I have two question indeed.
- how to write a pythonic ocaml code to format string.
If Ocaml cannot dynamically generate some string as format6 str and
pass it to sprintf? for code:let s = "%s" in Printf.sprintf s "hello"
would generate ERROR info as:
Error: This expression has type string
but an expression was expected of type
('a -> 'b, unit, string) format =
('a -> 'b, unit, string, string, string, string) format6
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果您的运算符以
#
字符开头,这实际上是可行的,因为该字符的优先级高于函数应用程序。This is actually doable if your operator starts with a
#
character, since that character has a higher precedence than function application.(1) 我认为没有比直接使用 Printf.sprintf 更好的方法了。我的意思是,您可以扩展您已经想出的内容:
它有效,但由于优先级所必需的括号而很难看。
(2) 在运行时生成格式字符串确实很难,因为格式字符串是在编译时解析的。它们可能看起来像字符串文字,但实际上它们是不同的类型,即“something format6”。 (它根据推断的类型确定您需要字符串还是格式字符串)事实上,格式字符串的确切类型取决于格式中的占位符;这是它能够对格式参数的数量和类型进行类型检查的唯一方法。最好不要弄乱格式字符串,因为它们与类型系统紧密相关。
(1) I don't think there's a good way to do it that is going to be nicer than using
Printf.sprintf
directly. I mean, you can extend what you've already come up with:which works, but is ugly because of the parentheses that are necessary for precedence.
(2) It's really hard to generate a format string at runtime because format strings are parsed at compile time. They may look like string literals, but they are actually a different type, which is "something format6". (it figures out whether you want a string or format string based on the inferred type) In fact, the exact type of a format string depends on what placeholders are in the format; that's the only way that it is able to type-check the number and types of format arguments. It's best not to mess with format strings because they are tied very heavily into the type system.
为什么要用一些动态格式替换静态检查的 sprintf ? OCaml 的 Printf 既使用紧凑又运行时安全。与 C printf 相比,C printf 紧凑但不安全,C++ 流安全但冗长。 Python 的格式并不比 C printf 更好(除了你得到的是异常而不是崩溃转储)。
唯一可以想象的用例是来自外部源的格式字符串。通常最好将其移至编译时。如果不可能,则只需回退到带有错误处理的手动动态格式化(正如已经说过的,您不能将 Printf 与动态格式字符串一起使用)。顺便说一句,这样的一个案例 - 国际化 - 包含在现有库中。一般来说,如果想要动态组合不同类型的多个值,则必须用变体(如
['S "hello"; 'I 20]
)包装它们并在打印端进行模式匹配。Why would one want to replace statically checked sprintf with some dynamic formatting? OCaml's Printf is both compact in usage and safe at runtime. Compare that to C printf which is compact but unsafe and C++ streams which are safe but verbose. Python's format is no way better than C printf (except that you get exception instead of crashdump).
The only imaginable use-case is format string coming from external source. And it is usually better to move it to compile-time. If it is not possible, then only one needs to fallback to manual dynamic formatting with error-handling (as already said you cannot use Printf with dynamic format string). BTW one such case - internationalization - is covered with existing libraries. Generally, if one wants to dynamically combine multiple values of different types, then one has to wrap them with variants (like
['S "hello"; 'I 20]
) and pattern-match at printing side.您应该查看 OCaml Batteries Included 的扩展/可扩展
printf
。我有一种感觉,你可以用它做你想做的事。You should check out OCaml Batteries Included's extended/extensible
printf
. I have the feeling that you can do what you want with it.如果我们绕过打字系统会怎样……
我并不认为这是最终的解决方案,但事实是这样据我查看邮件列表后得到的信息, http://pauillac .inria.fr/caml/FAQ/FAQ_EXPERT-eng.html#printf 和 ocaml 的 src。
What if we bypass the typing system...
I don't claim this to be the ultimate solution, but that's as far as I got after looking at the mailing list, http://pauillac.inria.fr/caml/FAQ/FAQ_EXPERT-eng.html#printf and ocaml's src.