奇怪的Ocaml类型错误



我正在编写一个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

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不变性的副作用:当你在顶层重新加载文件时,你实际上并没有改变任何第一次加载文件时建立的绑定,你只是创建了新的绑定。下面的例子演示了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

简而言之,您的代码包含了许多您错过的错误,因为您正在逐步将代码发送到顶层。

例如,在apply_binop_int中,您引用的是ExprTerm构造函数,它没有定义(稍后将定义它,但您可以只引用之前词法上出现的定义)。这就是为什么当您加载文件时,它会给您一个错误,并且没有定义apply_binop。但是类型是定义好的。在第二次尝试中定义了apply_binop,因为在前一次尝试中定义了所需的类型。但是一旦定义了apply_binop,就可以用新的定义隐藏expr类型。

相关内容

  • 没有找到相关文章

最新更新