Here my thoughts on your solution. But I'm also learning Haskell right now, so I'm not an expert..
You don't need the data type. You can use base 10 logarithm to get the number of digits. Like this:
(floor $ logBase 10 $ fromIntegral n) + 1
I like the fact that digs is tail recursive. It looks simpler without the data type:
digits :: Int -> [Int]
Read provides compatibility with ReadP.
parseInteger :: ReadP Int
parseInteger = readS_to_P $ readsPrec 0
parseDouble :: ReadP Double
parseDouble = readS_to_P $ readsPrec 0
Note that usually, Show instances are supposed to produce strings that can be pasted into .hs files to reproduce the value.
Why not have ObjFile = [ObjFileLine], and ObjFileLine as a ...
Why are you reimplementing length O_o?
dft_resolve_nested :: Double -> Int -> [((Double, Double), Double)] -> [(Double, Double)]
dft_resolve_nested _ _  = 
dft_resolve_nested k n (((x, y), t) : xs) = do
let angle = 2.0 * pi * t * k / fromIntegral n
let sumreal = x * cos angle + y * sin angle
let sumimag = - x * sin angle + y * cos angle
I'm also beginner, so not sure if can make a good review, but just want to notice. If you just need to replace a bunch of string (the list of colors), maybe it's better to use Aho-Corasick algorithm to find all matches and then just use fold through all matches. I did it for similar task.
I used ...
I don't think your code agrees with your spec: Your code looks like it can only implement a function built from three line segments.
You shouldn't need explicit resize.
bounce (lo, hi) x dx = let
(bounces, remainder) = divMod (add dx $ x-lo) $ hi-lo
in (if even bounces then lo + remainder else hi - remainder
,bounces /= 0)