Camlp4 解析器函数:表达式的类型为 int,但表达式应为 float 类型

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

我正在编写一个简单的解析器函数,它需要一个流中的项目,并且 returns 一个 int,但是出于某种原因,编译器出于我无法理解的原因一直期待一个浮点数;特别是考虑到代码是 actually example code from the llvm ocaml tutorial.

我试过将两个变量都类型转换为整数,并且通常只是摆弄语法,但函数太简单了,我无法弄清楚到底出了什么问题。我知道对于普通函数,可以使用 let: type->type 指定类型,但我不知道如何使用解析器函数。

函数如下:

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

以下是它的使用位置的更大上下文,以防这也是问题的一部分(尽管我认为不是):

    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" >] ->

我目前刚刚达到标准

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

输入错误。

有人知道为什么这会出现浮动吗?如何让函数期望一个 int?

编辑:

我现在意识到我现在措辞不当,但我意识到程序的上下文决定了函数的类型,我问的是程序中的什么使它假设函数返回一个整数。它似乎超出了我 post 编辑的范围,所以我正在用与显示的所有内容相关的代码更新我的 post。

这里是完整的组相关代码。很抱歉不包括这个开始。

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

错误的来源不在您显示的行中:有一个 Token 模块的实现以及 parse_first_argparse_operator 函数使您的代码编译.

有一件事可能很奇怪,你的 Token.Number 将浮点数作为参数。

另请注意,camlp4 及其解析器扩展已被废弃。

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

好吧,由于您没有向您展示代码,因此不可能告诉您代码哪里出错了,但我至少可以指出您对 OCaml 工作原理的概念性误解,希望它能帮助您修正你的代码 :)

在 OCaml 中,没有类型转换,你不能使一个函数来期望任何东西,因为类型是从你编写的代码中推断出来的。

比如这里有一个函数

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

它的类型被推断为 string -> int,在任何情况下,您都不能更改它,因为该类型基本上是由您的代码结构定义的。编译器会推断出您的 function/expression 适用的最一般上下文。

在我们的示例中,编译器知道 String.count 接受 string 类型的值,因此 s 也必须是 string 类型,它知道 String.count returns 类型的值 int 并且 (+) 只能应用于整数。因此,返回的类型是 int,仅此而已。

如果您要在不可接受的上下文中应用您的函数,

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

编译器告诉我们,表达式 number_of_words "hello, world" 的类型为 int,但它的类型应为 string。这不是因为我们的表达式是错误的,而是因为我们在错误的上下文中使用它,在预期 string 的上下文中,所以 int 不适合它。您的情况也是如此,您在 prec 需要 float 值的地方使用。换句话说,你试图修复错误的地方。

回到我们的例子,正确的表达是

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

这里string_of_float不是强制转换操作符,不是类型转换操作符,OCaml中不存在这样的操作符,否则是不健全的。它是一个函数,将类型 int 的值转换为类型 string 的值,即,它创建一个新字符串,然后用与数字对应的十进制数字填充它,例如,

  string_of_int 42
  - : string = "42"

returns 一个包含两个字符的字符串,不是一个整数,被转换成一个字符串。

希望对您有所帮助。此外,在玩 OCaml Kaleidoscope 之前学习一些 OCaml 教程是个好主意,这是一个非常高级、过时且非常不惯用的 OCaml 编程示例。