-1

I am defining a primitive type in OCaml, this is a homework. Everything works fine but I got an error with implemented Dict type. The code:

type ide = string;;

type exp = Eint of int | Ebool of bool | Den of ide | Prod of exp * exp | Sum of exp * exp | Diff of exp * exp |
    Eq of exp * exp | Minus of exp | IsZero of exp | Or of exp * exp | And of exp * exp | Not of exp |
    Ifthenelse of exp * exp * exp | Let of ide * exp * exp | Fun of ide * exp | FunCall of exp * exp |
    Letrec of ide * exp * exp| Dict of (ide * exp) list;;

type 't env = ide -> 't;;
let emptyenv (v : 't) = function x -> v;;
let applyenv (r : 't env) (i : ide) = r i;;
let bind (r : 't env) (i : ide) (v : 't) = function x -> if x = i then v else applyenv r x;;

type evT = Int of int | Bool of bool | Unbound | FunVal of evFun | RecFunVal of ide * evFun | DictVal of (ide * evT) list
and evFun = ide * exp * evT env;;

let typecheck (s : string) (v : evT) : bool = match s with
    "int" -> (match v with
        Int(_) -> true |
        _ -> false) |
    "bool" -> (match v with
        Bool(_) -> true |
        _ -> false) |
    _ -> failwith("not a valid type");;


let prod x y = if (typecheck "int" x) && (typecheck "int" y)
    then (match (x,y) with
        (Int(n),Int(u)) -> Int(n*u))
    else failwith("Type error");;

let sum x y = if (typecheck "int" x) && (typecheck "int" y)
    then (match (x,y) with
        (Int(n),Int(u)) -> Int(n+u))
    else failwith("Type error");;

let diff x y = if (typecheck "int" x) && (typecheck "int" y)
    then (match (x,y) with
        (Int(n),Int(u)) -> Int(n-u))
    else failwith("Type error");;

let eq x y = if (typecheck "int" x) && (typecheck "int" y)
    then (match (x,y) with
        (Int(n),Int(u)) -> Bool(n=u))
    else failwith("Type error");;

let minus x = if (typecheck "int" x) 
    then (match x with
        Int(n) -> Int(-n))
    else failwith("Type error");;

let iszero x = if (typecheck "int" x)
    then (match x with
        Int(n) -> Bool(n=0))
    else failwith("Type error");;

let vel x y = if (typecheck "bool" x) && (typecheck "bool" y)
    then (match (x,y) with
        (Bool(b),Bool(e)) -> (Bool(b||e)))
    else failwith("Type error");;

let et x y = if (typecheck "bool" x) && (typecheck "bool" y)
    then (match (x,y) with
        (Bool(b),Bool(e)) -> Bool(b&&e))
    else failwith("Type error");;

let non x = if (typecheck "bool" x)
    then (match x with
        Bool(true) -> Bool(false) |
        Bool(false) -> Bool(true))
    else failwith("Type error");;


let rec eval (e : exp) (r : evT env) : evT = match e with

    Dict(pairs) -> DictVal(evalDictList pairs r) |
    Eint n -> Int n |
    Ebool b -> Bool b |
    IsZero a -> iszero (eval a r) |
    Den i -> applyenv r i |
    Eq(a, b) -> eq (eval a r) (eval b r) |
    Prod(a, b) -> prod (eval a r) (eval b r) |
    Sum(a, b) -> sum (eval a r) (eval b r) |
    Diff(a, b) -> diff (eval a r) (eval b r) |
    Minus a -> minus (eval a r) |
    And(a, b) -> et (eval a r) (eval b r) |
    Or(a, b) -> vel (eval a r) (eval b r) |
    Not a -> non (eval a r) |
    Ifthenelse(a, b, c) -> 
        let g = (eval a r) in
            if (typecheck "bool" g) 
                then (if g = Bool(true) then (eval b r) else (eval c r))
                else failwith ("nonboolean guard") |
    Let(i, e1, e2) -> eval e2 (bind r i (eval e1 r)) |
    Fun(i, a) -> FunVal(i, a, r) |
    FunCall(f, eArg) -> 
        let fClosure = (eval f r) in
            (match fClosure with
                FunVal(arg, fBody, fDecEnv) -> 
                    eval fBody (bind fDecEnv arg (eval eArg r)) |
                RecFunVal(g, (arg, fBody, fDecEnv)) -> 
                    let aVal = (eval eArg r) in
                        let rEnv = (bind fDecEnv g fClosure) in
                            let aEnv = (bind rEnv arg aVal) in
                                eval fBody aEnv |
                _ -> failwith("non functional value")) |
        Letrec(f, funDef, letBody) ->
                (match funDef with
                    Fun(i, fBody) -> let r1 = (bind r f (RecFunVal(f, (i, fBody, r)))) in
                                                    eval letBody r1 |
                    _ -> failwith("non functional def"))            

    and evalDictList (pairs : (ide * exp) list) (r : evT env) : (ide * evT) list = match pairs with
        [ ] -> [ ] |
        (key,value) :: other -> (key, eval value r) :: evalDictList other r;;

Everything works fine but when I do:

let mydict = Dict("test", Eint 2);;

or Dict("test", Eint 2);;

I get this error: Error: This expression has type 'a * 'b but an expression was expected of type (ide * exp) list.

This homework consist in writing a basic interpreter for a language with the above primitive types.

user4789408
  • 1,196
  • 3
  • 14
  • 31
  • 1
    Please don't just dump all your code here and expect us to figure it out for you. Make a [mcve]. The process of doing so would most likely have led you to figure this out yourself. – glennsl Jan 05 '19 at 12:36
  • Using a GADT here would remove a ton of the `failwith("Type error")` calls. (e.g. see [Writing an interpreter with OCaml GADTs](https://stackoverflow.com/questions/41797085/writing-an-interpreter-with-ocaml-gadts)) – Kevin Ji Jan 06 '19 at 21:50

1 Answers1

0

The error is a bit more general and obfuscated than it needs to be, but points directly at the problem. If I replace the type variables 'a and 'b in the error with the actual types, you'll probably see it immediately:

Error: This expression has type ide * exp but an expression was expected of type (ide * exp) list.

That is, you're giving Dict a tuple (of something), but it's expecting a list of tuples (with some specific types) because it's defined as Dict of (ide * exp) list.

Wrapping the tuple in a list will make it compile:

let mydict = Dict [("test", Eint 2)];;
glennsl
  • 28,186
  • 12
  • 57
  • 75
  • This is working! What If I don't want to use Dict[("test", Eint 2)] but directly a type of exp? I mean how could I use Dict[("Test", 54646)]? – user4789408 Jan 05 '19 at 12:56
  • That's not possible, presumably because it would make the type inference undecidable. What if there was a `type exp2 = EInt2 of int` for example, and how would it disambiguate `Prod` and `Or`? Even if technically possible, the rules for how this would work would likely be very complicated. – glennsl Jan 05 '19 at 13:07
  • what if I want to set multiple element inside the Dict? Dict is (ide * exp) list – user4789408 Jan 05 '19 at 22:14
  • `Dict [("test", Eint 2); ("test2", Ebool true)];;`? This is pretty basic (unless I'm misunderstanding the question) and something you should have gone through long before this kind of assignment. If you find you have lots of questions like this you might want to go through the earlier material again. – glennsl Jan 05 '19 at 23:07