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_arg
和 parse_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 编程示例。
我正在编写一个简单的解析器函数,它需要一个流中的项目,并且 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_arg
和 parse_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 编程示例。