[英]How to pass parameter to Shell.sh_one in Ocaml
When I pass bytes variable to the method Shell.sh_one
from Core_extended
there is a strange error: 当我将字节变量从Core_extended
传递给方法Shell.sh_one
, Core_extended
出现一个奇怪的错误:
Error: This expression has type bytes but an expression was expected of
type
('a, unit, bytes, bytes option) Core.Std.format4 =
('a, unit, bytes, bytes, bytes, bytes option) format6
What's interesting if I'll pass bytes literal, there is no error. 有趣的是,如果我传递字节文字,没有错误。 Could someone explain this behaviour of Ocaml? 有人可以解释Ocaml的这种行为吗? Below there is a listing from Ocaml utop: 下面是Ocaml utop的列表:
# #require "core_extended";;
# open Core_extended.Std;;
# let cmd = "ls -al /";;
val cmd : bytes = "ls -al /"
# "ls -al /";;
- : bytes = "ls -al /"
# Shell.sh_one "ls -al /";;
- : bytes option =
Some
"lrwxrwxrwx 1 root root 30 sty 29 09:28 vmlinuz.old -> boot/vmlinuz-4.13.0-32-generic"
# Shell.sh_one cmd;;
Error: This expression has type bytes but an expression was expected of type
('a, unit, bytes, bytes option) Core.Std.format4 =
('a, unit, bytes, bytes, bytes, bytes option) format6
If you look at the type of Core_extended.Shell.sh_one
, you will see the following 如果查看Core_extended.Shell.sh_one
的类型,您将看到以下内容
val sh_one: ('a,unit,bytes,string option) format4 -> 'a
This means that the first argument of sh_one
is a format string. 这意味着sh_one
的第一个参数是格式字符串。 For instance, one can use format specifier with sh_one
: 例如,可以将格式说明符与sh_one
一起sh_one
:
Shell.sh_one "ls -%s /" "al"
Your issue stems from the fact that format string type, format4
, and string or bytes are not the same type in OCaml. 您的问题源于格式字符串类型,格式format4
和字符串或字节在OCaml中的类型不同。
Nevertheless, there is a bit of magic in the OCaml typechecker that makes it possible for strings and format strings to share the same literal syntax: if the typechecker notices that the expected type of string literal is in fact a format string, it reinterpret the string literal as a format string literal. 然而,OCaml类型检查器中有一点神奇之处在于它使字符串和格式字符串可以共享相同的文字语法:如果类型检查器注意到预期的字符串文字类型实际上是格式字符串,它会重新解释字符串文字作为格式字符串文字。
You can have a look a the phenomenon by yourself in utop by comparing 你可以通过比较自己在utop看看这个现象
let s = "A simple string";;
s : string = "A simple string" s:string =“一个简单的字符串”
and 和
open CamlinternalFormatBasics
(* ^ this help with making the format readable *)
let fmt : _ format4 = "A format string"
val fmt : ('a, 'b, 'c, 'a) format4 = Format (String_literal ("A simple string", End_of_format), "A simple string") val fmt:('a,'b,'c,'a)format4 =格式(String_literal(“一个简单的字符串”,End_of_format),“一个简单的字符串”)
An alternative to the explicit type annotation is to use the format_of_string
function which marks a string literal as format string literal 显式类型注释的替代方法是使用format_of_string
函数,该函数将字符串文字标记为格式字符串文字
let fmt = format_of_string "A format string"
In brief, if you want to store a format string inside a variable you can either use an explicit type annotation or format_of_string
简而言之,如果要在变量中存储格式字符串,可以使用显式类型注释或format_of_string
Though they are syntactically identical, the bytes
and format
types are different. 虽然它们在语法上是相同的,但bytes
和format
类型是不同的。
That is handled by some dark magic inside the compiler which basically checks when it sees a string if it is bound to a format type. 这是由编译器内部的一些黑魔法处理的,它基本上检查它何时看到字符串,如果它绑定到格式类型。
In your case, the check is performed at the creation of cmd
. 在您的情况下,检查是在创建cmd
。 At this point in the program, there is no way to know that it will be used as a format string. 在程序的这一点上,没有办法知道它将被用作格式字符串。 So it is given the type bytes
. 所以它给出了类型bytes
。 Later, you get to the usual "I don't do transtyping" from the obviously puzzled compiler. 后来,你从明显困惑的编译器中得到了通常的“我不做转换”。
let cmd : ('a,'b,'c,'d) Core.Std.format4 = "ls -al /";;
Here I just added a type information so that the compiler knows that "this is not a string, but a format string". 这里我只添加了一个类型信息,以便编译器知道“这不是字符串,而是格式字符串”。 Things should just work fine with that. 事情应该正常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.