let evaluate_op value1 value2 operator =
        let string_of_operator = function
                | Plus -> "+"
                | Minus -> "-"
                | Times -> "*"
                | Divide -> "/"
                | Modulo -> "%"
                | Or -> "||"
                | And -> "&&"
        in let string_op s1 s2 =
                (match operator with
                        | Plus -> RStringValue(s1 ^ s2)
                        | _ -> raise (EInvalidOperation (string_of_operator operator,"string"))
                )
        in let float_op f1 f2 = (let f = (match operator with
                                        | Plus -> f1 +. f2
                                        | Minus -> f1 -. f2
                                        | Times -> f1 *. f2
                                        | Divide -> f1 /. f2
                                        | _ -> raise (EInvalidOperation (string_of_operator operator,"float"))) in
                         RFloatValue(f)
                )
        in match (value1, value2) with
        | (RIntegerValue(i1), RIntegerValue(i2)) ->
                        (match operator with
                                | Plus -> RIntegerValue( i1 + i2 )
                                | Minus -> RIntegerValue( i1 - i2)
                                | Times -> RIntegerValue( i1 * i2)
                                | Divide -> RIntegerValue( i1 / i2) 
                                | Modulo -> RIntegerValue( i1 mod i2)
                                | _ -> raise (EInvalidOperation (string_of_operator operator,"integer"))
                        )
        | (RBooleanValue(b1), RBooleanValue(b2)) ->
                        (match operator with
                                | And -> RBooleanValue(b1 && b2)
                                | Or -> RBooleanValue(b1 || b2)
                                | _ -> raise (EInvalidOperation (string_of_operator operator,"boolean"))
                        )
        | (RFloatValue(f1), RFloatValue(f2)) -> float_op f1 f2
        | (RFloatValue(f1), RIntegerValue(i2)) -> float_op f1 (float_of_int i2)
        | (RIntegerValue(i1), RFloatValue(f2)) -> float_op (float_of_int i1) f2
        | (RStringValue(s1), RStringValue(s2)) -> string_op s1 s2
        | (RStringValue(s1), v2) -> string_op s1 (string_of_value v2)
        | (v1, RStringValue(s2)) -> string_op (string_of_value v1) s2
        | (value1, value2) -> raise (EIncompatibleTypes(string_of_value_type value1, string_of_value_type value2))