Joshua Meier
Joshua Meier

Reputation: 1

Ocaml Type Mismatch? Expected Unit but is a defined type

I get the error below and I cannot figure out why this is the case. any help is appreciated. the program is an interpreter in Ocaml. The piece of code being underlined by tryOcaml is the last bit of code "processor tokens [];;" Not sure why that would be the type mismatch or where the mismatch happens in the code.

Error: This expression has type stackValue list but an expression was expected of type unit

type stackValue = NUM of int | BOOL of bool | ERROR | STRING of string | NAME of string | UNIT

type com = PUSH of stackValue | POP | ADD | SUB | MUL | DIV | REM | NEG | SWAP | QUIT | TOSTRING | PRINTLN (*| CAT | AND | OR | NOT | LESSTHAN | EQUAL | IF | BIND let com {com} end | funBind com {com} [return] funEnd | call*)

let interpreter ( (inFile : string), (outFile : string )) : unit = 
let ic = open_in inFile 
in
let oc = open_out outFile 
in

let rec loop_read acc =
  try 
      let l = String.trim(input_line ic) in loop_read (l::acc)
  with
  | End_of_file -> List.rev acc 
  in

  let ls_str = loop_read [] 
  in
let checkrest s = 
  match s.[0] with
  | '"' ->  if s.[(String.length s) -1]='"' then STRING(String.sub s 1 ((String.length s)-2)) else ERROR
  | '-' | '0'..'9' -> (try NUM(int_of_string s) with _ ->ERROR)
  | '_' | 'a'..'z' | 'A'..'Z' -> NAME(s)
  |_ -> ERROR
  in

  let str2sv s =
    match s with
    |":true:" -> BOOL(true)
    |":false:" -> BOOL(false)
    |":unit:" -> UNIT
    |":error:" -> ERROR
    |_-> checkrest s 
    in

  let str2com s = 
    match s with 
    |"quit" -> QUIT
    |"add" -> ADD
    |"sub" -> SUB
    |"mul" -> MUL
    |"div" -> DIV
    |"rem" -> REM
    |"pop" -> POP
    |"neg" -> NEG
    |"swap" -> SWAP
    (*|"cat" -> CAT
    |"and" -> AND
    |"or" -> OR
    |"not" -> NOT
    |"lessthan" -> LESSTHAN
    |"equal" -> EQUAL
    |"if" -> IF
    |"bind" -> BIND*)
    |"toString" -> TOSTRING
    |_ -> if String.sub s 0 4 = "push" then let x = str2sv (String.sub s 5 ((String.length s) -5)) in PUSH(x) else PUSH(ERROR)
    in

let tokens = List.map str2com ls_str
in

let sv2str sv =
  match sv with
  |BOOL(true) -> STRING(":true:")
  |BOOL(false) -> STRING(":false:")
  |UNIT -> STRING(":unit:")
  |ERROR -> STRING(":error:")
  |STRING(s) -> STRING(s)
  |NAME(s) -> STRING(s)
  |NUM(x) -> STRING(string_of_int(x))
in

let file_write value = Printf.fprintf oc "%s\n" value 
in

let rec processor comlist stack =
  match (comlist,stack) with
  |(PUSH(x)::comst, stack) -> processor comst (x::stack)
  |(POP::comst, stackValue::reststack) -> processor comst reststack
  |(POP::comst, []) -> processor comst (ERROR::stack)
  |(ADD::comst, NUM(a)::NUM(b)::reststack) -> processor comst (NUM(a+b)::reststack)
  |(ADD::comst, stack) -> processor comst (ERROR::stack)
  |(SUB::comst, NUM(a)::NUM(b)::reststack) -> processor comst (NUM(b-a)::reststack)
  |(SUB::comst, stack) -> processor comst (ERROR::stack)
  |(MUL::comst, NUM(a)::NUM(b)::reststack) -> processor comst (NUM(a*b)::reststack)
  |(MUL::comst, stack) -> processor comst (ERROR::stack)
  |(DIV::comst, NUM(a)::NUM(b)::reststack) -> if (NUM(a)=NUM(0)) then (processor comst (ERROR::NUM(a)::NUM(b)::reststack)) else (processor comst (NUM(b/a)::reststack))
  |(DIV::comst, stack) -> processor comst (ERROR::stack)
  |(REM::comst, NUM(a)::NUM(b)::reststack) -> if (NUM(a)=NUM(0)) then (processor comst (ERROR::NUM(a)::NUM(b)::reststack)) else (processor comst (NUM(b mod a)::reststack))
  |(REM::comst, stack) -> processor comst (ERROR::stack)
  |(NEG::comst, NUM(a)::reststack) -> processor comst (NUM(-a)::reststack)
  |(NEG::comst, stack) -> processor comst (ERROR::stack)
  |(SWAP::comst, x::xs::reststack) -> processor comst (xs::x::reststack)
  |(SWAP::comst, stack) -> processor comst (ERROR::stack)
  |(TOSTRING::comst, x::reststack) -> let s = sv2str x in processor comst (s::reststack)
  |(TOSTRING::comst, []) -> processor comst (ERROR::stack)
  |(PRINTLN::comst, x::reststack) -> (match x with 
                                        |STRING(x) -> file_write x; processor comst reststack
                                        |_ -> ERROR::stack)
  |(PRINTLN::comst, []) -> processor comst (ERROR::stack)
  |(QUIT::comst, stack) -> []
  |(_,_) -> []

in
processor tokens [];;

Upvotes: 0

Views: 148

Answers (1)

ivg
ivg

Reputation: 35210

Let me minimize your code to highlight the problem,

let interpreter ( (inFile : string), (outFile : string )) : unit = 
  ... <snip> ...
let rec processor comlist stack =
  match (comlist,stack) with
  |(PUSH(x)::comst, stack) -> processor comst (x::stack)
  |(QUIT::comst, stack) -> []
  ... <snip> ...
  |(_,_) -> []

in
processor tokens []

Take a second and look carefully at the snippet above, do you see the problem? If not yet, then answer the following questions:

  1. What type of value does processor function return?
  2. What type of value the interpreter shall return?

E.g., consider processor [] [], it will return [] therefore we can see that processor tokens [] is a value of type _ list, but you have an annotation : unit that says that your interpreter input output shall evaluate to a value of type unit where instead it evaluates to a stack.

If you really don't need the stack, you can ignore it,

ignore (processor tokens [])

where ignore is a simple function, that has roughly the following implementation,

let ignore x = ()

i.e., it just ignores its argument so that it has type 'a -> unit. Instead of using ignore you can also write,

let _stack = processor tokens [] in
()

So you ignore the returned stack (the convention is to prefix with an underscope an ignored value) and return the () value instead of the _stack.

Upvotes: 1

Related Questions