我正在编写一个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
答案 0 :(得分:2)
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上重新加载文件时,你实际上并没有改变你第一次加载文件时建立的任何绑定,你是&#39 ;只是创造新的。以下示例演示了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
答案 1 :(得分:1)
简而言之,您的代码包含许多错误,您错过了,因为您正在逐步将代码发送到顶层。
例如,在apply_binop_int
中你指的是ExprTerm
构造函数,它没有定义(它将在后面定义,但你可能只会引用以前词汇发生的定义)。这就是为什么当您加载文件时,它会给您一个错误,并且未定义apply_binop
。但是类型是定义的。第二次尝试定义了apply_binop
,因为在之前的尝试中定义了所需的类型。但是,在您定义apply_binop
时,您会立即隐藏expr
类型并使用新定义。