如何将参数传递给Ocaml中的Shell.sh_one

问题描述 投票:1回答:2

当我从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

有趣的是,如果我传递字节文字,没有错误。有人可以解释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
ocaml ocaml-core
2个回答
1
投票

虽然它们在语法上是相同的,但是bytesformat类型是不同的。

这是由编译器内部的一些黑魔法处理的,它基本上检查它何时看到字符串,如果它绑定到格式类型。

在您的情况下,检查是在创建cmd时执行的。在程序的这一点上,没有办法知道它将被用作格式字符串。所以给它类型bytes。后来,你从明显困惑的编译器中得到了通常的“我不做转换”。

let cmd : ('a,'b,'c,'d) Core.Std.format4 = "ls -al /";;

这里我只添加了一个类型信息,以便编译器知道“这不是字符串,而是格式字符串”。事情应该正常。


2
投票

如果你看一下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 =“一个简单的字符串”

 open CamlinternalFormatBasics 
(* ^ this help with making the format readable *)
 let fmt : _ format4 = "A format string"

val fmt:('a,'b,'c,'a)format4 =格式(String_literal(“一个简单的字符串”,End_of_format),“一个简单的字符串”)

显式类型注释的替代方法是使用format_of_string函数,该函数将字符串文字标记为格式字符串文字

 let fmt = format_of_string "A format string"

简而言之,如果要在变量中存储格式字符串,可以使用显式类型注释或format_of_string

© www.soinside.com 2019 - 2024. All rights reserved.