这个问题的发生远远超过^
运营商。基本上,OCaml编译器需要知道您的格式字符串是一个文字字符串,并且在编译时需要知道文字字符串。否则,OCaml无法在编译时将这个字符串强制转换为BLAHBLAH format6
类型。 Printf
模块只能在编译时完全知道的格式字符串或已经转换为BLAHBLAH format
类型的格式字符串正确工作。
一般来说,你可以通过使用^^
运营商,并通过在代码中使用这些字符串明确铸造的所有文字字符串到的BLAHBLAH format
型之前解决这个问题。
下面是另一个例子:
# Printf.sprintf (if true then "%d" else "%d ") 2;;
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
(* define a type abbreviation for brevity *)
# type ('a,'b) fformat = ('a ->'b, unit, string) format;;
type ('a, 'b) fformat = ('a -> 'b, unit, string) format
# Printf.sprintf (if true then ("%d":('a,'b)fformat) else ("%d ":('a,'b)fformat)) 2;;
- : string = "2"
OCaml的系统无法识别if ... then "a" else "b"
可强制转换为BLAHBLAH format
。如果您将每个文字字符串自己改为BLAHBLAH format
,那么一切正常。 (注意:如果你试图将整个if/then/else
转换为BLAHBLAH format
,因为OCaml中无法验证您的字符串字面它不工作。)
问题的起源是类型安全的要求:OCaml的要求有是每个%d
和%s
等的正确类型的参数,并且保证这在编译时间。除非在编译时间已知整个格式字符串,否则不能保证类型安全。因此,不可能将Printf
与通过复杂算法计算的格式串一起使用,例如通过随机选择%s
和%d
。
当我们使用if/then/else
来计算格式字符串时,OCaml的东西,哦,这是一个复杂的算法,在编译时验证类型安全是无望的。 ^^
运算符知道约BLAHBLAH format
类型,并在连接格式字符串时产生正确的结果。但if/then/else
不知道BLAHBLAH format
,并没有内置的替代if/then/else
(但我想你可以自己定义这样的事情)。
一个很好的解释,谢谢。一个小点,我觉得你的表述“(^^)操作符创建一个输入上下文..”不清楚;这个运算符在里面没有魔术,只是输入'... format - > ... format - > ... format',并且类型推断做了检查它的参数是这种类型的常量字符串的工作。 – gasche
gasche是对的。需要理解的是,当你给“Print。* printf”一个字符串时,你不给它一个'Pervasives.string'类型的值,你给它一个'Pervasives.format6'类型的值(这不是等于'Pervasives.string')。 –
对,我应该说,(^^)有gasche给出的类型。这部分绝对没有魔法。唯一的魔法(据我所知)是在将字符串常量提升为适当的'format'类型。 –