evalExpr ::    (binOp -> Int -> Int -> Int)
               -- ^ How to evaluate binary operators
            -> (expr -> Int)
               -- ^ How to evaluate expressions
            -> Expression binOp expr
               -- ^ `Expression` value to evaluate
            -> Int
               -- ^ Evaluation returns some Int
evalExpr evalBinOp' evalExpr' expr =
  case expr of
    ExprInt i        -> evalExprInt i
    ExprBinOp l op r -> evalExprBinOp evalBinOp' evalExpr' l op r
--


-- | Evaluate a `BinOp` value. Note that this is simply applying `evalAdd` and
--   `evalSub` to the `BinOp` ADT.
evalExpr ::    (binOp -> Int -> Int -> Int)
               -- ^ How to evaluate binary operators
            -> (expr -> Int)
               -- ^ How to evaluate expressions
            -> Expression binOp expr
               -- ^ `Expression` value to evaluate
            -> Int
evalExpr evalBinOp' evalExpr' expr =
  case expr of
    ExprInt i        -> evalExprInt i
    ExprBinOp l op r -> evalExprBinOp evalBinOp' evalExpr' l op r
--


-- | Evaluate a `BinOp` value. Note that this is simply applying `evalAdd` and
--   `evalSub` to the `BinOp` ADT.
evalExpr evalBinOp' evalExpr' expr =
  case expr of
    ExprInt i        -> evalExprInt i
    ExprBinOp l op r -> evalExprBinOp evalBinOp' evalExpr' l op r
--


-- | Evaluate a `BinOp` value. Note that this is simply applying `evalAdd` and
--   `evalSub` to the `BinOp` ADT.