binOpTypes op e1 e2
    | isNum op = case (texprType e1, texprType e2) of
                     (IntType, IntType) -> return IntType
                     (DoubleType, DoubleType) -> return DoubleType
                     _ -> throwError $ show (e1,e2) ++ 
                                       " are unsuitable arguments for " ++ 
                                       show op
    | isBool op =  case (texprType e1, texprType e2) of
                     (BoolType, BoolType) -> return BoolType
                     _ -> throwError $ show (e1,e2) ++ 
                                       " are unsuitable arguments for " ++ 
                                       show op
binOpTypes op e1 e2
    | isNum op = case (texprType e1, texprType e2) of
                     (IntType, IntType) -> return IntType
                     (DoubleType, DoubleType) -> return DoubleType
                     _ -> throwError $ show (e1,e2) ++ 
                                       " are unsuitable arguments for " ++ 
                                       show op
    | isBool op =  case (texprType e1, texprType e2) of
                     (BoolType, BoolType) -> return BoolType
                     _ -> throwError $ show (e1,e2) ++ 
                                       " are unsuitable arguments for " ++ 
                                       show op
binOpTypes op e1 e2
    | isNum op = case (texprType e1, texprType e2) of
                     (IntType, IntType) -> return IntType
                     (DoubleType, DoubleType) -> return DoubleType
                     _ -> throwError $ show (e1,e2) ++ 
                                       " are unsuitable arguments for " ++ 
                                       show op
    | isBool op =  case (texprType e1, texprType e2) of
                     (BoolType, BoolType) -> return BoolType
                     _ -> throwError $ show (e1,e2) ++ 
                                       " are unsuitable arguments for " ++ 
                                       show op