ocamlcamlp4

Camlp4 Parser function: expression has type int but an expression was expected of type float


I was writing a simple parser function that expects an item in a stream, and returns an int, but for some reason the compiler keeps expecting a float for reasons I can't comprehend; especially considering that the code is actually example code from the llvm ocaml tutorial.

I've tried type casting both variables to ints, and just generally fiddling around with the syntax, but the function is so simple I can't figure out what's actually wrong. I know that one can, for a normal function, specify the type with let: type->type but I don't know how that would work with a parser function.

here's the function:

    let parse_binary_precedence = parser 
        | [< 'Token.Number n >] -> int_of_float n
        | [< >] -> 30 
    in

Here's the greater context of where it is used in case that is also part of the problem (although, I don't think it is):

    let parse_binary_precedence = parser 
        | [< 'Token.Number n >] -> (int_of_float n)
        | [< >] -> 30 
    in
    parser 
        | [< (prefix, kind)=parse_operator; 
            'Token.Kwd op ?? "expected operator";
            prec = parse_binary_precedence;
            'Token.Kwd '(' ?? "expected '(' in operator prototype"; 
            args = parse_first_arg []; 
            'Token.Kwd ')' ?? "expected ')' in operator protoype" >] ->

I currently am just getting the standard

File "parser.ml", line 108, characters 49-50:
Error: This expression has type int but an expression was expected of type
         float

type error.

Does anybody know why this is expecting a float? How do I make the function expect an int?

EDIT:

I realize now that i've phrased it poorly now, but I realize that the context of the program is what decides the type of the function, I was asking about what within the program was making it assume that the function returned an int. It seems that it is outside of the scope of what i posted, so I'm updating my post with the code relating to everything shown.

Here is the full set of the relevant code. apologies for not including this to begin with.

token.ml:

type token = 
    (*primary*)
    | Ident of string | Number of int
    (*control*)
    | If | Else | For 
    (*user ops*)
    | Binary | Unary

parser.ml

let parse_prototype = 
    let rec parse_args accumulator = parser
        | [< 'Token.Kwd ','; 'Token.Ident id; e=parse_args (id :: accumulator) >] -> e
        | [< >] -> accumulator 
    in

    let parse_first_arg accumulator = parser
        | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e
        | [< >] -> accumulator
    in
    let parse_operator = parser
        | [< 'Token.Binary >] -> "binary", 2
        | [< 'Token.Unary >] -> "unary", 1
    in
    let parse_binary_precedence = parser 
        | [< 'Token.Number n >] -> (int_of_float n) (*line 108*)
        | [< >] -> 30 
    in
    parser 
        | [< 'Token.Ident id;
            'Token.Kwd '(' ?? "expected '(' in prototype";
            args= parse_first_arg [];
            'Token.Kwd ')' ?? "expected closing ')' in prototype " >] ->
            Ast.Prototype (id, Array.of_list (List.rev args))
        | [< (prefix, kind)=parse_operator; 
            'Token.Kwd op ?? "expected operator";
            prec = parse_binary_precedence;
            'Token.Kwd '(' ?? "expected '(' in operator prototype"; 
            args = parse_first_arg [];
            'Token.Kwd ')' ?? "expected ')' in operator protoype" >] ->
            let name = prefix ^ (String.make 1 op) in
            let args = Array.of_list (List.rev args) in 

            (*verify right number of args for op*)
            if Array.length args != kind then
                raise (Stream.Error "invalid number of operands in op def")
            else 
                if kind == 1 then 
                    Ast.Prototype (name, args)
                else 
                    Ast.BinOpPrototype (name, args, prec)
        | [< >] ->
                raise (Stream.Error "expected func name in prototype")

ast.ml

type proto = 
    | Prototype of string * string array
    | BinOpPrototype of string * string array * int

Solution

  • Does anybody know why this is expecting a float? How do I make the function expect an int?

    Well, it is impossible to tell you where your code went wrong since you're not showing you code, but I can at least point you on your conceptual misunderstanding of how OCaml works, hoping that it will help you to fix your code :)

    In OCaml, there is no typecasting and you can't make a function to expect anything, because types are inferred from the code that you have written.

    For example, here is a function

     let number_of_words s = String.count s ~f:(Char.is_whitespace) + 1
    

    it's type is inferred as string -> int and under no circumstances, you can change it, because the type is fundamentally defined by the structure of your code. It is the compiler that infers the most general context in which your function/expression is applicable.

    In our example, the compiler knows that String.count accepts a value of type string therefore s must be also of type string, it knows that String.count returns a value of type int and that (+) could be applied only to integers. Therefore, the returned type is int and nothing more.

    If you will apply your function in an unacceptable context,

    "the phrase has " ^ number_of_words "hello, world"
    

    the compiler us, that the expression number_of_words "hello, world" has type int but it is expected to have type string. And this is not because our expression is wrong, it is because we're using it in a wrong context, in a context where a string is expected, so int just doesn't fit it. The same is in your case, you're using prec in the place where a float value is expected. In other words, you're trying to fix in the wrong place.

    Going back to our example, the correct expression will be

     "the phrase has " ^ string_of_int (number_of_words "hello, world")
    

    Here string_of_float is not a coercion operator, not a type casting operator, nothing like this exists in OCaml, as otherwise, it will be unsound. It is a function that translates a value of type int into a value of type string, i.e., it creates a new string and then fills it in with decimal digits the correspond to the number, e.g.,

      string_of_int 42
      - : string = "42"
    

    returns a string with two characters, not an integer, casted into a string.

    Hope it helps. Also, it would be a good idea to take some tutorials in OCaml, before playing with OCaml Kaleidoscope, which is a pretty advanced, outdated, and very non-idiomatic example of OCaml programming.