ocamlocaml-core

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:

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? Below there is a listing from 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

Solution

  • Though they are syntactically identical, the bytes and format types are different.

    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. 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. 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.