map0 ::
     (Show b, Eq b, Field b, Exponentiative b)
  => (String -> b)
  -> (a -> b)
  -> (Fn a -> b)
  -> (Expression a -> b -> b)
  -> Expression a
  -> b
map0 mapVar mapConst mapFun mapApplyFun e0 = rec e0
  where
    rec e =
      case e of
        Const a -> mapConst a
        Var a   -> mapVar a
        Fun f   -> mapFun f
        App f a -> mapApplyFun f (rec a)
        Neg a   -> neg (rec a)
        Sum a b -> rec a + rec b
        Prd a b -> rec a * rec b
        Rcp a   -> reciprocal (rec a)
        Pow a b -> rec a ^ rec b
        Log a b -> log (rec a) (rec b)

--  trace ("evalExpr: " ++ nm ++ " -> " ++ show val ++ " in " ++ show exp) $
map0 ::
     (Show b, Eq b, Field b, Exponentiative b)
  => (String -> b)
  -> (a -> b)
  -> (Fn a -> b)
  -> (Expression a -> b -> b)
  -> Expression a
  -> b
map0 mapVar mapConst mapFun mapApplyFun e0 = rec e0
  where
    rec e =
      case e of
        Const a -> mapConst a
        Var a   -> mapVar a
        Fun f   -> mapFun f
        App f a -> mapApplyFun f (rec a)
        Neg a   -> neg (rec a)
        Sum a b -> rec a + rec b
        Prd a b -> rec a * rec b
        Rcp a   -> reciprocal (rec a)
        Pow a b -> rec a ^ rec b
        Log a b -> log (rec a) (rec b)

--  trace ("evalExpr: " ++ nm ++ " -> " ++ show val ++ " in " ++ show exp) $
map0 mapVar mapConst mapFun mapApplyFun e0 = rec e0
  where
    rec e =
      case e of
        Const a -> mapConst a
        Var a   -> mapVar a
        Fun f   -> mapFun f
        App f a -> mapApplyFun f (rec a)
        Neg a   -> neg (rec a)
        Sum a b -> rec a + rec b
        Prd a b -> rec a * rec b
        Rcp a   -> reciprocal (rec a)
        Pow a b -> rec a ^ rec b
        Log a b -> log (rec a) (rec b)

--  trace ("evalExpr: " ++ nm ++ " -> " ++ show val ++ " in " ++ show exp) $