First some style advice:
lg s e a
| s >= e = a
| even s = lg (s+1) e (a+1)
| otherwise = lg (s+1) e (a*2)
Regarding your question: lg is not really a loop. It's a tail-recursive function, but that alone doesn't say much in Haskell. The main thing that gets in the way is lazyness: if the accumulators are only accumulated in the thunk-dimension, rather than their values, lazyness merely builds up an enourmous amount of overhead without any usability gain.
A simple way to prevent this is to evaluate arguments strictly, with
{-# LANGUAGE BangPatterns #-}
lg' s e !a
| s >= e = a
| even s = lg' (s+1) e (a+1)
| otherwise = lg' (s+1) e (a*2)
However, because of such issues but also because of conciseness/modularity/..., it is rather preferred not to write tail-recursive functions at all but use higher level-tools – list comprehensions themselves are often not that great performance-wise, but if you express your algorithms in terms of generic folds etc. you can utilise much more performant data structures such as unboxed vectors with little changes to your code.