Anatoliy Sokolov
Anatoliy Sokolov

Reputation: 397

How to extract a value from a type Ocaml

I have a type

type expr =   
Const of int 
| Var of string    
| Bin of expr * binop * expr 

also

type binop = 
 Plus 
| Minus 
| Mul 
| Div 

and

type value =  
Int of int               
| Closure of env * string option * string * expr 

Binop performs an operation on two exprs and I need to write an eval function that takes in a closure and expr and returns a value

ex.

 let evn = [("z1",Int 0);("x",Int 1);("y",Int 2);("z",Int 3);("z1",Int 4)];;
val evn : (string * Nano.value) list =
  [("z1", Int 0); ("x", Int 1); ("y", Int 2); ("z", Int 3); ("z1", Int 4)]

# let e1 = Bin(Bin(Var "x",Plus,Var "y"), Minus, Bin(Var "z",Plus,Var "z1"));;
val e1 : Nano.expr =
  Bin (Bin (Var "x", Plus, Var "y"), Minus, Bin (Var "z", Plus, Var "z1"))

# eval (evn, e1);;
- : Nano.value = Int 0

The issue Im having is that the function needs to return INT int instead of an actual into value.

This is what I wrote so far

let rec eval (evn,e) = match e with
| Const a -> Int a
| Var x-> Int (lookup (x,evn) )
| Bin( Var x, Plus, Var y) ->   Int ( eval(evn,Var x) + eval(evn,Var y) )
| Bin( Var x, Minus, Var y) -> Int ( eval(evn,Var x) + eval(evn,Var y) )
| Bin( Var x, Mul, Var y) ->   Int ( eval(evn,Var x) + eval(evn,Var y) )
| Bin( Var x, Div, Var y) ->  Int ( eval(evn,Var x) + eval(evn,Var y) )

;;

lookup looks up x in the closure evn and returns its value the issue Im having is I need to perform integer operations in the bin matches but since eval returns types of value I cant do that. How would I change the code in the last four matches to make it be able to do the arithmetic and return type Int of int after that's done?

Upvotes: 3

Views: 2997

Answers (2)

V. Michel
V. Michel

Reputation: 1619

let rec eval (evn,e) = match e with
| Const a -> Int a
| Var x-> Int (lookup (x,evn) )
| Bin(  el, Plus,  er) ->
    let Int cl=eval (evn,el ) and Int cr=eval (evn,er ) in
    Int (cl+cr)
| Bin(  el, Minus,  er) ->
    let Int cl=eval (evn,el ) and Int cr=eval (evn,er ) in
    Int (cl-cr)
| Bin(  el, Mul,  er) ->
    let Int cl=eval (evn,el ) and Int cr=eval (evn,er ) in
    Int (cl*cr)
| Bin(  el, Div,  er) ->
    let Int cl=eval (evn,el ) and Int cr=eval (evn,er ) in
    Int (cl/cr)

Upvotes: 2

antron
antron

Reputation: 3847

You need something like

let x =
  match eval (evn, Var x) with
  | Int x -> x
  | _ -> failwith "runtime error"
in

let y =
  match eval (evn, Var y) with
  | Int y -> y
  | _ -> failwith "runtime error"
in

Int (x + y)

in each of the match cases. You should probably factor out this pattern-match into a function that you can call repeatedly:

let get_int = function
  | Int i -> i
  | _ -> failwith "runtime error: expected an integer"

... Int ((eval (evn, e1) |> get_int) + (eval (evn, e2) |> get_int))

It should make sense that you have to do this runtime check in your evaluator – in your representation, there is no reason why a variable can't be mapped to a closure in evn instead of an integer.

Also note that, contrary to your question, evn itself is not a closure. It's usually called the "environment". The closures are the values constructed by Closure, and they carry environments, among other things – I think you simply had a typo, though.

I'm assuming that you will generalize the Var x and Var y to two expressions e and e' in the future, of course.

Upvotes: 2

Related Questions