Q:

Implementation of (^)

I was reading the code of the implementation of (^) of the standard haskell library : 
(^) :: (Num a, Integral b) => a -> b -> a
x0 ^ y0 | y0 < 0    = errorWithoutStackTrace "Negative exponent"
        | y0 == 0   = 1
        | otherwise = f x0 y0
    where -- f : x0 ^ y0 = x ^ y
          f x y | even y    = f (x * x) (y `quot` 2)
                | y == 1    = x
                | otherwise = g (x * x) ((y - 1) `quot` 2) x
          -- g : x0 ^ y0 = (x ^ y) * z
          g x y z | even y = g (x * x) (y `quot` 2) z
                  | y == 1 = x * z
                  | otherwise = g (x * x) ((y - 1) `quot` 2) (x * z)

Now this part where g is defined seems odd to me why not just implement it like this:
expo :: (Num a ,Integral b) => a -> b ->a
expo x0 y0 
    | y0 == 0 = 1
    | y0 <  0 = errorWithoutStackTrace "Negative exponent"
    | otherwise = f x0 y0
    where
      f x y | even y = f (x*x) (y `quot` 2)
              | y==1 = x
              | otherwise = x * f  x (y-1)

But indeed plugging in say 3^1000000 shows that (^) is about 0,04 seconds faster than expo.  

Why is (^) faster than expo? 

A:

As the person who wrote the code, I can tell you why it's complex.   :)
The idea is to be tail recursive to get loops, and also to perform the minimum number of multiplications.   I don't like the complexity, so if you find a more elegant way please file a bug report.  

A:

A function is tail-recursive if the return value of a recursive call is returned as-is, without further processing.  In expo, f is not tail-recursive, because of otherwise = x * f  x (y-1): the return value of f is multiplied by x before it is returned.  Both f and g in (^) are tail-recursive, because their return values are returned unmodified. 
Why does this matter?  Tail-recursive functions can implemented much more efficiently than general recursive functions.  Because the compiler doesn't need to create a new context (stack frame, what have you) for a recursive call, it can reuse the caller's context as the context of the recursive call.  This saves a lot of the overhead of calling a function, much like in-lining a function is more efficient than calling the function proper.