Haskell function to error-diffuse a floating value to a list of integers











up vote
3
down vote

favorite












I needed to write a function which would 'error diffuse' floating values to integers:



errorDiffuse :: Double -> Int -> Double -> [Int]

errorDiffuse _ 0 _ =

errorDiffuse v num err = tv : errorDiffuse v (num - 1) (err + v - fromIntegral tv)
where tv = truncate (v + err)


So that, for example:



errorDiffuse 1.4 10 0 => [1,1,2,1,1,2,1,2,1,1]


(i.e., the function produces a list of num integers, each of which is the ceiling or floor of v, starting with a given error value (zero in this case)).



Is there a better way to write this sort of for loop? What's the higher-order function I ought to be thinking in terms of?










share|improve this question




























    up vote
    3
    down vote

    favorite












    I needed to write a function which would 'error diffuse' floating values to integers:



    errorDiffuse :: Double -> Int -> Double -> [Int]

    errorDiffuse _ 0 _ =

    errorDiffuse v num err = tv : errorDiffuse v (num - 1) (err + v - fromIntegral tv)
    where tv = truncate (v + err)


    So that, for example:



    errorDiffuse 1.4 10 0 => [1,1,2,1,1,2,1,2,1,1]


    (i.e., the function produces a list of num integers, each of which is the ceiling or floor of v, starting with a given error value (zero in this case)).



    Is there a better way to write this sort of for loop? What's the higher-order function I ought to be thinking in terms of?










    share|improve this question


























      up vote
      3
      down vote

      favorite









      up vote
      3
      down vote

      favorite











      I needed to write a function which would 'error diffuse' floating values to integers:



      errorDiffuse :: Double -> Int -> Double -> [Int]

      errorDiffuse _ 0 _ =

      errorDiffuse v num err = tv : errorDiffuse v (num - 1) (err + v - fromIntegral tv)
      where tv = truncate (v + err)


      So that, for example:



      errorDiffuse 1.4 10 0 => [1,1,2,1,1,2,1,2,1,1]


      (i.e., the function produces a list of num integers, each of which is the ceiling or floor of v, starting with a given error value (zero in this case)).



      Is there a better way to write this sort of for loop? What's the higher-order function I ought to be thinking in terms of?










      share|improve this question















      I needed to write a function which would 'error diffuse' floating values to integers:



      errorDiffuse :: Double -> Int -> Double -> [Int]

      errorDiffuse _ 0 _ =

      errorDiffuse v num err = tv : errorDiffuse v (num - 1) (err + v - fromIntegral tv)
      where tv = truncate (v + err)


      So that, for example:



      errorDiffuse 1.4 10 0 => [1,1,2,1,1,2,1,2,1,1]


      (i.e., the function produces a list of num integers, each of which is the ceiling or floor of v, starting with a given error value (zero in this case)).



      Is there a better way to write this sort of for loop? What's the higher-order function I ought to be thinking in terms of?







      haskell






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 19 at 20:43









      200_success

      127k15148411




      127k15148411










      asked Nov 2 '11 at 14:12









      stusmith

      17517




      17517






















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          3
          down vote



          accepted










          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





          share|improve this answer





















          • Fantastic, thankyou! I don't think unfoldr is in my mental toolkit yet but it was exactly the sort of thing I was thinking of.
            – stusmith
            Nov 2 '11 at 16:34










          • Glad I could help :-)
            – Nicolas Wu
            Nov 2 '11 at 16:37










          • unfoldr is a great tool to add to your toolkit. Whenever you need to produce a list from some seed value(s), unfoldr should come to mind.
            – Dan Burton
            Nov 26 '11 at 20:03











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














           

          draft saved


          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f5757%2fhaskell-function-to-error-diffuse-a-floating-value-to-a-list-of-integers%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          3
          down vote



          accepted










          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





          share|improve this answer





















          • Fantastic, thankyou! I don't think unfoldr is in my mental toolkit yet but it was exactly the sort of thing I was thinking of.
            – stusmith
            Nov 2 '11 at 16:34










          • Glad I could help :-)
            – Nicolas Wu
            Nov 2 '11 at 16:37










          • unfoldr is a great tool to add to your toolkit. Whenever you need to produce a list from some seed value(s), unfoldr should come to mind.
            – Dan Burton
            Nov 26 '11 at 20:03















          up vote
          3
          down vote



          accepted










          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





          share|improve this answer





















          • Fantastic, thankyou! I don't think unfoldr is in my mental toolkit yet but it was exactly the sort of thing I was thinking of.
            – stusmith
            Nov 2 '11 at 16:34










          • Glad I could help :-)
            – Nicolas Wu
            Nov 2 '11 at 16:37










          • unfoldr is a great tool to add to your toolkit. Whenever you need to produce a list from some seed value(s), unfoldr should come to mind.
            – Dan Burton
            Nov 26 '11 at 20:03













          up vote
          3
          down vote



          accepted







          up vote
          3
          down vote



          accepted






          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





          share|improve this answer












          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






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 2 '11 at 15:45









          Nicolas Wu

          21112




          21112












          • Fantastic, thankyou! I don't think unfoldr is in my mental toolkit yet but it was exactly the sort of thing I was thinking of.
            – stusmith
            Nov 2 '11 at 16:34










          • Glad I could help :-)
            – Nicolas Wu
            Nov 2 '11 at 16:37










          • unfoldr is a great tool to add to your toolkit. Whenever you need to produce a list from some seed value(s), unfoldr should come to mind.
            – Dan Burton
            Nov 26 '11 at 20:03


















          • Fantastic, thankyou! I don't think unfoldr is in my mental toolkit yet but it was exactly the sort of thing I was thinking of.
            – stusmith
            Nov 2 '11 at 16:34










          • Glad I could help :-)
            – Nicolas Wu
            Nov 2 '11 at 16:37










          • unfoldr is a great tool to add to your toolkit. Whenever you need to produce a list from some seed value(s), unfoldr should come to mind.
            – Dan Burton
            Nov 26 '11 at 20:03
















          Fantastic, thankyou! I don't think unfoldr is in my mental toolkit yet but it was exactly the sort of thing I was thinking of.
          – stusmith
          Nov 2 '11 at 16:34




          Fantastic, thankyou! I don't think unfoldr is in my mental toolkit yet but it was exactly the sort of thing I was thinking of.
          – stusmith
          Nov 2 '11 at 16:34












          Glad I could help :-)
          – Nicolas Wu
          Nov 2 '11 at 16:37




          Glad I could help :-)
          – Nicolas Wu
          Nov 2 '11 at 16:37












          unfoldr is a great tool to add to your toolkit. Whenever you need to produce a list from some seed value(s), unfoldr should come to mind.
          – Dan Burton
          Nov 26 '11 at 20:03




          unfoldr is a great tool to add to your toolkit. Whenever you need to produce a list from some seed value(s), unfoldr should come to mind.
          – Dan Burton
          Nov 26 '11 at 20:03


















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f5757%2fhaskell-function-to-error-diffuse-a-floating-value-to-a-list-of-integers%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Morgemoulin

          Scott Moir

          Souastre