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