【问题标题】:How to pass parameter to Shell.sh_one in Ocaml如何在 Ocaml 中将参数传递给 Shell.sh_one
【发布时间】:2018-08-14 11:36:54
【问题描述】:

当我将字节变量从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

【问题讨论】:

    标签: ocaml ocaml-core


    【解决方案1】:

    如果查看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 = 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

    【讨论】:

      【解决方案2】:

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

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

      在您的情况下,检查是在创建cmd 时执行的。此时在程序中,没有办法知道它会被用作格式字符串。所以它的类型是bytes。稍后,您会从明显感到困惑的编译器中得到通常的“我不进行转换”。

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

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

      【讨论】:

      • 如果我将命令字符串存储在某个变量中怎么办?在这种情况下,我无法使用您的解决方案,因为它仅适用于文字。是否可以从bytes 变量创建format4?我知道Scanf.format_from_string 创建format6format4 呢?
      • @trivelt format6format4 是兼容的(后者是前者的别名),所以你应该可以使用该函数。
      猜你喜欢
      • 2020-08-18
      • 2021-09-18
      • 2011-01-27
      • 2014-10-16
      • 2020-02-04
      • 2019-12-29
      • 1970-01-01
      • 2018-05-28
      • 2013-09-25
      相关资源
      最近更新 更多