The usual way now to write it would be as:
length3 :: [a] -> Int
length3 = go 0
where
go :: Int -> [a] -> Int
go n [] = n
go n (x:xs) = n `seq` go (n+1) xs
Namely, as a fold over the list strict in the accumulator. GHC yields the direct translation to Core:
Main.$wgo :: forall a_abz. GHC.Prim.Int# -> [a_abz] -> GHC.Prim.Int#
Main.$wgo =
\ (n :: GHC.Prim.Int#) (xs :: [a_abz]) ->
case xs of
[] -> n
_ : xs -> Main.$wgo a (GHC.Prim.+# n 1) xs
Showing that it is unboxed (and thus strict) in the accumulator.