如何在 Ocaml 中将参数传递给 Shell.sh_one
How to pass parameter to Shell.sh_one in Ocaml
当我将字节变量从 Core_extended
传递给方法 Shell.sh_one
时,出现了一个奇怪的错误:
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
有趣的是,如果我传递字节文字,没有错误。有人可以解释 Ocaml 的这种行为吗?下面是 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
虽然语法相同,但 bytes
和 format
类型不同。
这是由编译器内部的一些黑魔法处理的,它基本上会在看到字符串时检查它是否绑定到格式类型。
在您的例子中,检查是在创建 cmd
时执行的。此时在程序中,没有办法知道它将被用作格式字符串。所以它被赋予类型bytes
。稍后,您会从明显困惑的编译器中得到通常的 "I don't do transtyping"。
let cmd : ('a,'b,'c,'d) Core.Std.format4 = "ls -al /";;
这里我只是加了一个类型信息,让编译器知道"this is not a string, but a format string"。事情应该可以正常进行。
如果您查看 Core_extended.Shell.sh_one
的类型,您将看到以下内容
val sh_one: ('a,unit,bytes,string option) format4 -> 'a
这意味着sh_one
的第一个参数是格式字符串。例如,可以将格式说明符与 sh_one
:
一起使用
Shell.sh_one "ls -%s /" "al"
您的问题源于格式字符串类型 format4
和字符串或字节在 OCaml 中不是同一类型。
然而,OCaml 类型检查器中有一些神奇之处,可以让字符串和格式字符串共享相同的文字语法:如果类型检查器注意到字符串文字的预期类型实际上是格式字符串, 它将字符串文字重新解释为格式字符串文字。
你可以在utop中通过对比自己看看现象
let s = "A simple string";;
s : string = "A simple string"
和
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")
显式类型注释的替代方法是使用 format_of_string
函数,该函数将字符串文字标记为格式字符串文字
let fmt = format_of_string "A format string"
简而言之,如果您想在变量中存储格式字符串,您可以使用显式类型注释或 format_of_string
当我将字节变量从 Core_extended
传递给方法 Shell.sh_one
时,出现了一个奇怪的错误:
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
有趣的是,如果我传递字节文字,没有错误。有人可以解释 Ocaml 的这种行为吗?下面是 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
虽然语法相同,但 bytes
和 format
类型不同。
这是由编译器内部的一些黑魔法处理的,它基本上会在看到字符串时检查它是否绑定到格式类型。
在您的例子中,检查是在创建 cmd
时执行的。此时在程序中,没有办法知道它将被用作格式字符串。所以它被赋予类型bytes
。稍后,您会从明显困惑的编译器中得到通常的 "I don't do transtyping"。
let cmd : ('a,'b,'c,'d) Core.Std.format4 = "ls -al /";;
这里我只是加了一个类型信息,让编译器知道"this is not a string, but a format string"。事情应该可以正常进行。
如果您查看 Core_extended.Shell.sh_one
的类型,您将看到以下内容
val sh_one: ('a,unit,bytes,string option) format4 -> 'a
这意味着sh_one
的第一个参数是格式字符串。例如,可以将格式说明符与 sh_one
:
Shell.sh_one "ls -%s /" "al"
您的问题源于格式字符串类型 format4
和字符串或字节在 OCaml 中不是同一类型。
然而,OCaml 类型检查器中有一些神奇之处,可以让字符串和格式字符串共享相同的文字语法:如果类型检查器注意到字符串文字的预期类型实际上是格式字符串, 它将字符串文字重新解释为格式字符串文字。
你可以在utop中通过对比自己看看现象
let s = "A simple string";;
s : string = "A simple string"
和
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")
显式类型注释的替代方法是使用 format_of_string
函数,该函数将字符串文字标记为格式字符串文字
let fmt = format_of_string "A format string"
简而言之,如果您想在变量中存储格式字符串,您可以使用显式类型注释或 format_of_string