First I'd get rid of the dependency on num, since that's just a counter,
and you can use take num on an infinite list of errorDiffuses:
errorDiffuses :: Double -> Double -> [Int]
errorDiffuses v err = tv : errorDiffuses v (err + v - fromIntegral tv)
where
tv = truncate (v + err)
So we have:
errorDiffuse' :: Double -> Int -> Double -> [Int]
errorDiffuse' v num err = take num $ errorDiffuses v err
Then I'd think about generating the list of errorDiffuses differently.
Since we're trying to generate a list, that makes me think of unfolds,
which you can find in Data.List:
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
The unfold takes a function that, given a seed, produces the next
value in the outputted list, along with a new seed. The function
starts with an intitial seed, and keeps using those seeds, adding to the
list until the function returns Nothing.
The function we're looking for is the following:
nextErrorDiffuse :: Double -> Double -> Maybe (Int, Double)
nextErrorDiffuse v err = Just (tv, err + v - fromIntegral tv)
where
tv = truncate (v + err)
Our list is infinite, so we always return a Just value. The value that is output at each stage is tv, and the next "seed" is given by err + v - fromIntegral tv.
Putting things together we have:
errorDiffuse'' :: Double -> Int -> Double -> [Int]
errorDiffuse'' v num err = take num $ unfoldr (nextErrorDiffuse v) err