奇怪的 Ocaml 类型错误
Strange Ocaml type error
我正在编写一个 ocaml 程序来处理基本算术命令和符号数学命令。但是,该代码目前给我一个奇怪的类型错误。我觉得这可能会出现,因为有两种不同的变体使用 binop 类型,但我不确定。
open Core.Std
type binop =
|Add
|Subtract
|Multiply
|Divide
let apply_binop_int a b = function
|Add -> a + b
|Subtract -> a - b
|Multiply -> a * b
|Divide -> a / b
let rec apply_binop a b op =
match (a,b) with
|ExprTerm (Const a), ExprTerm (Const b) -> apply_binop_int a b op
|BinopExpr (op1,a1,b1),_ -> apply_binop (apply_binop a1 b1 op1) b op
|_,BinopExpr (op1,a1,b1) -> apply_binop a (apply_binop a1 b1 op1) op
let precedence = function
|Add |Subtract -> 0
|Multiply |Divide -> 1
type term =
|Const of int
|Var of string
type token =
|Term of term
|Operator of binop
type expr =
|ExprTerm of term
|BinopExpr of binop * expr * expr
let operator_of_string = function
|"+" -> Add
|"-" -> Subtract
|"*" -> Multiply
|"/" -> Divide
|_ -> failwith "Unidentified operator"
let token_of_string s =
try Term (Const (int_of_string s))with
|_ -> Operator (operator_of_string s)
let tokens s =
String.split ~on:' ' s
|> List.map ~f:token_of_string
let process_operator ops exprs =
match (ops,exprs) with
|op::op_tl,b::a::expr_tl -> op_tl,(BinopExpr (op,a,b))::expr_tl
|_,_ -> failwith "Malformed expression"
let rec pop_stack (ops,exprs) =
match (ops,exprs) with
|_::_, _::_::_ -> pop_stack (process_operator ops exprs)
|_,[x] -> x
|_,_ -> failwith "Malformed expression"
let build_expr ts =
let rec aux ops exprs toks =
match (toks,ops) with
|Term t::tl,_ -> aux ops ((ExprTerm t)::exprs) tl
|Operator op2::tl,op::_ when precedence op >= precedence op2 ->
let ops,exprs = process_operator ops exprs in
aux ops exprs toks
|Operator op::tl,_ -> aux (op::ops) exprs tl
|[],_ -> pop_stack (ops,exprs) in
aux [] [] ts
let expr s = build_expr (tokens s)
let rec eval = function
|BinopExpr (op,a,b) ->
apply_binop (eval a) (eval b) op
|ExprTerm t -> t
我遇到的错误:
utop # #use "calc.ml";;
type binop = Add | Subtract | Multiply | Divide
val apply_binop_int : int -> int -> binop -> int = <fun>
File "calc.ml", line 18, characters 63-66:
Error: This expression has type binop/1405061 but an expression was expected of type
binop/1740597
简而言之,您的代码包含很多您错过的错误,因为您正在逐步将代码发送到顶层。
例如,在 apply_binop_int
中,您指的是未定义的 ExprTerm
构造函数(稍后将对其进行定义,但您可以仅引用之前词法上出现的定义)。这就是为什么当你加载一个文件时,它给你一个错误,并且 apply_binop
没有定义。但是类型是有定义的。第二次尝试定义了 apply_binop
,因为在之前的尝试中定义了所需的类型。但是一旦你定义了 apply_binop
,你就用新的定义隐藏了 expr
类型。
OCaml 惯例是始终定义类型,然后定义对这些类型进行操作的函数。另外,我喜欢默认将我的类型定义为相互递归的,因为它使代码更容易阅读:
type binop =
Add of term * term
| Subtract of term * term
| Multiply of term * term
| Divide of term * term
and term =
Const of int
| Var of string;;
ivg 是正确的,OCaml 只允许您在程序中定义函数和类型后使用它们,但是如上面的示例所示,在您的定义中使用 and
可以覆盖它。
至于这个错误:
Error: This expression has type binop/1405061 but an expression was expected of type
binop/1740597
这实际上是 OCaml 不变性的副作用:当您在 TopLevel 上重新加载文件时,您实际上并没有更改第一次加载文件时建立的任何绑定,您只是在创建新的绑定.以下示例演示了 OCaml 的 属性:
utop # let x = 7;;
val x : int = 7
utop # let arg_times_7 arg = arg * x;;
val arg_times_7 : int -> int = <fun>
utop # arg_times_7 6;;
- : int = 42
utop # let x = 6912;;
val x : int = 6912
utop # arg_times_7 6;;
- : int = 42
我正在编写一个 ocaml 程序来处理基本算术命令和符号数学命令。但是,该代码目前给我一个奇怪的类型错误。我觉得这可能会出现,因为有两种不同的变体使用 binop 类型,但我不确定。
open Core.Std
type binop =
|Add
|Subtract
|Multiply
|Divide
let apply_binop_int a b = function
|Add -> a + b
|Subtract -> a - b
|Multiply -> a * b
|Divide -> a / b
let rec apply_binop a b op =
match (a,b) with
|ExprTerm (Const a), ExprTerm (Const b) -> apply_binop_int a b op
|BinopExpr (op1,a1,b1),_ -> apply_binop (apply_binop a1 b1 op1) b op
|_,BinopExpr (op1,a1,b1) -> apply_binop a (apply_binop a1 b1 op1) op
let precedence = function
|Add |Subtract -> 0
|Multiply |Divide -> 1
type term =
|Const of int
|Var of string
type token =
|Term of term
|Operator of binop
type expr =
|ExprTerm of term
|BinopExpr of binop * expr * expr
let operator_of_string = function
|"+" -> Add
|"-" -> Subtract
|"*" -> Multiply
|"/" -> Divide
|_ -> failwith "Unidentified operator"
let token_of_string s =
try Term (Const (int_of_string s))with
|_ -> Operator (operator_of_string s)
let tokens s =
String.split ~on:' ' s
|> List.map ~f:token_of_string
let process_operator ops exprs =
match (ops,exprs) with
|op::op_tl,b::a::expr_tl -> op_tl,(BinopExpr (op,a,b))::expr_tl
|_,_ -> failwith "Malformed expression"
let rec pop_stack (ops,exprs) =
match (ops,exprs) with
|_::_, _::_::_ -> pop_stack (process_operator ops exprs)
|_,[x] -> x
|_,_ -> failwith "Malformed expression"
let build_expr ts =
let rec aux ops exprs toks =
match (toks,ops) with
|Term t::tl,_ -> aux ops ((ExprTerm t)::exprs) tl
|Operator op2::tl,op::_ when precedence op >= precedence op2 ->
let ops,exprs = process_operator ops exprs in
aux ops exprs toks
|Operator op::tl,_ -> aux (op::ops) exprs tl
|[],_ -> pop_stack (ops,exprs) in
aux [] [] ts
let expr s = build_expr (tokens s)
let rec eval = function
|BinopExpr (op,a,b) ->
apply_binop (eval a) (eval b) op
|ExprTerm t -> t
我遇到的错误:
utop # #use "calc.ml";;
type binop = Add | Subtract | Multiply | Divide
val apply_binop_int : int -> int -> binop -> int = <fun>
File "calc.ml", line 18, characters 63-66:
Error: This expression has type binop/1405061 but an expression was expected of type
binop/1740597
简而言之,您的代码包含很多您错过的错误,因为您正在逐步将代码发送到顶层。
例如,在 apply_binop_int
中,您指的是未定义的 ExprTerm
构造函数(稍后将对其进行定义,但您可以仅引用之前词法上出现的定义)。这就是为什么当你加载一个文件时,它给你一个错误,并且 apply_binop
没有定义。但是类型是有定义的。第二次尝试定义了 apply_binop
,因为在之前的尝试中定义了所需的类型。但是一旦你定义了 apply_binop
,你就用新的定义隐藏了 expr
类型。
OCaml 惯例是始终定义类型,然后定义对这些类型进行操作的函数。另外,我喜欢默认将我的类型定义为相互递归的,因为它使代码更容易阅读:
type binop =
Add of term * term
| Subtract of term * term
| Multiply of term * term
| Divide of term * term
and term =
Const of int
| Var of string;;
ivg 是正确的,OCaml 只允许您在程序中定义函数和类型后使用它们,但是如上面的示例所示,在您的定义中使用 and
可以覆盖它。
至于这个错误:
Error: This expression has type binop/1405061 but an expression was expected of type
binop/1740597
这实际上是 OCaml 不变性的副作用:当您在 TopLevel 上重新加载文件时,您实际上并没有更改第一次加载文件时建立的任何绑定,您只是在创建新的绑定.以下示例演示了 OCaml 的 属性:
utop # let x = 7;;
val x : int = 7
utop # let arg_times_7 arg = arg * x;;
val arg_times_7 : int -> int = <fun>
utop # arg_times_7 6;;
- : int = 42
utop # let x = 6912;;
val x : int = 6912
utop # arg_times_7 6;;
- : int = 42