Haskell function to format a floating-point number with some precision
Here's another way to write it (without changing too much). The functions toString and padZereos do sensible things on their own, so I kept them in the global namespace. Everything else is local. Having one big where-clause where you define everything local to a function is something you'll see often. Note that due to lazy evaluation you can define a_trimmed and a_padded, even if only one is used, so the other is never calculated. That further cleans up the code.

In a next step, I'd probably get rid of calc entirely, and fold sign handling into its body. Also, normalize looks like it should be calculated with divMod or quotRem.

showEngFloat :: RealFloat a =&gt; Int -&gt; a -&gt; [Char]
showEngFloat precision x = result where
  result = if x &gt;= 0 then calc x else '-' : calc (-x)
  normalize :: Int -&gt; (Int,Int)
  normalize dp = loop dp 0 where
    loop dp e
      | dp &gt; 3 = loop (dp - 3) (e+3)
      | dp &lt; 1 = loop (dp + 3) (e-3)
      | otherwise = (dp,e)
  calc n = a ++ "." ++ b ++ "E" ++ c where
    (digits,dotPos0) = floatToDigits 10 n
    ndigits = length digits
    (dotPos1,e) = normalize dotPos0
    a_trimmed = toString (take dotPos1 digits)
    a_padded  = padZeroes (dotPos1 - ndigits) (toString (take ndigits digits))
    a = if ndigits &gt;= dotPos1 then a_trimmed else a_padded
    b = padZeroes (precision - max dotPos1 ndigits) (toString (drop dotPos1 digits))
    c = toString [e]