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