2015-08-06 5 views
0

Я пишу программу ocaml для обработки основных арифметических команд и символических математических команд. Тем не менее, код в настоящее время дает мне странную ошибку типа. Я чувствую, что это может возникнуть, потому что есть два разных варианта, которые используют тип бинопа, но я не уверен.Ошибка Strange Ocaml

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 

ответ

1

Короче говоря, ваш код содержит много ошибок, которые вы пропустили, так как вы пошаговы отправке коды в верхний уровень.

Например, в apply_binop_int вы ссылаетесь на конструктор ExprTerm, который не определен (он будет определен позже, но вы можете ссылаться только на определения, которые встречаются лексически раньше). Поэтому, когда вы загружаете файл, это дает вам ошибку, и apply_binop не определен. Но типы определены. Во второй попытке определяется apply_binop, потому что при предыдущей попытке были определены необходимые типы. Но как только вы определяете apply_binop, вы спрячете expr с новым определением.

+0

Итак, я изменил код таким образом, чтобы все объявления типа были сделаны первым, и, похоже, это исправить проблему. Это единственная ошибка, о которой вы говорили, или есть другие? – Nezo

+0

да, это просто подразумевало много других ошибок :) – ivg

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;; 

ИДК является правильным, OCaml только позволяет использовать функции и типы после того как они были определенный в программе, но, как показывает вышеприведенный пример, использование and в ваших определениях может переопределить это.

В этой ошибки:

Error: This expression has type binop/1405061 but an expression was expected of type    

бинарным оператором/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 
Смежные вопросы