This code is used in Learn You A Haskell to explain how (++) can be inefficient if it is used to build out a list to the right instead of to the left:
import Control.Monad.Writer
gcdReverse :: Int -> Int -> Writer [String] Int
gcdReverse a b
| b == 0 = do
tell ["Finished with " ++ show a]
return a
| otherwise = do
result <- gcdReverse b (a `mod` b)
tell [show a ++ " mod " ++ show b ++ " = " ++ show (a `mod` b)]
return result
Since we are not doing tail recursion here is it correct to assume that GHC will transform this function into a CPS style function during compilation? If this transform is in fact happening can I expect it from all Haskell compilers, or is it just a GHC thing.
I understand this function is inefficient because it is appending the list the wrong way, but I just want to make sure there won’t cause a stack overflow.
No, GHC does not do CPS conversion. Although there are variants of the CPS conversion for lazy languages, I know of no compiler for a lazy language which actually performs CPS conversion.
You’re right in that CPS conversion can trade stack space for heap space, but some compilers which employs the CPS conversion treats the continuations specially so that they effectively get a heap allocated stack, and so you will get a stack overflow anyway. I think this is a good thing because it helps debugging. And, as for heap allocated stacks, GHC does that too, without CPS conversion. That’s how it deals with its lightweight threads implementation.