title: Evaluation of higher-order functions
body: <p>I've written a function <code>getSamplesFromFile</code> that takes a file and returns its contents as a <code>Vector</code> of <code>Floats</code>. The functions reads the contents of the file into a <code>Data.ByteString</code> using <code>Data.ByteString.hGet</code>, it then converts this <code>Data.ByteString</code> to a <code>Vector</code> of <code>Floats</code> using:</p>
  
  <pre><code>import qualified Data.Vector.Unboxed as V
  import qualified Data.ByteString as BS
  import Data.Word
  import System.Environment
  import GHC.Int
  toVector :: BS.ByteString -&gt; V.Vector Float
  toVector bs =  vgenerate (fromIntegral (BS.length bs `div` 3)) $ \i -&gt;
       myToFloat [BS.index bs (3*i), BS.index bs (3*i+1), BS.index bs (3*i+2)]
    where
      myToFloat :: [Word8] -&gt; Float
      myToFloat = sum . map fromIntegral 
  
  vgenerate n f = V.generate n (f . fromIntegral)
  </code></pre>
  
  <p>I was testing how lazy this program was via a small test program:</p>
  
  <pre><code>main = do
      [file] &lt;- getArgs
      samples &lt;- getSamplesFromFile file
      let slice = V.slice 0 50000 samples
      print slice
  </code></pre>
  
  <p>If I run this on a 13MB file, it seems as if every sample is loaded into memory, even though I only need 50000 samples to be printed. 
  <a href="https://i.stack.imgur.com/9ZFEu.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/9ZFEu.png" alt="enter image description here"></a>
  If I make a small modification to this problem and first map or filter over it, the result is different:</p>
  
  <pre><code>main = do
      [file] &lt;- getArgs
      samples &lt;- getSamplesFromFile file
      let slice = V.slice 0 50000 samples
      let mapped = V.map id slice
      print mapped
  </code></pre>
  
  <p>This way, it seems that not every sample was loaded into memory, only the slice:
  <a href="https://i.stack.imgur.com/0Gwsn.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/0Gwsn.png" alt="enter image description here"></a>
  To make sure this was the case, I ran the program again with a slice of half the size (25000 samples):
  <a href="https://i.stack.imgur.com/4XcMN.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/4XcMN.png" alt="enter image description here"></a>
  Now, the memory usage seems to be proportional to the size of the slice. Just because I map over the slice with <code>id</code>. </p>
  
  <p>The result is the same when filtering over the samples. How can applying a higher-order function suddenly make the behavior lazy?</p>
  
  <p><strong>EDIT</strong>
  The problem seems to have to do something with <code>cabal</code>. As you can see from the pictures, I was testing my code inside a <code>cabal</code> project called <em>laziness</em>. I can't reproduce this weird behavior if use a separate <code>Main.hs</code> file outside of a cabal project. This is the <code>Main.hs</code> I'm using:</p>
  
  <pre><code>module Main where
  
  import qualified Data.ByteString     as BS
  import qualified Data.Vector.Unboxed as V
  import           Data.Word
  import           GHC.Int
  import           System.Environment
  main = do
      [file] &lt;- getArgs
      samples &lt;- getSamplesFromFile file
      let slice = V.slice 0 50000 samples
      --let filtered = V.filter (&gt;0) slice
      let mapped = V.map id slice
      print slice
  
  getSamplesFromFile = fmap toVector . BS.readFile
  
  toVector :: BS.ByteString -&gt; V.Vector Float
  toVector bs =  vgenerate (fromIntegral (BS.length bs `div` 3)) $ \i -&gt;
       myToFloat [BS.index bs (3*i), BS.index bs (3*i+1), BS.index bs (3*i+2)]
    where
      myToFloat :: [Word8] -&gt; Float
      myToFloat = sum . map fromIntegral
  
  vgenerate n f = V.generate n (f . fromIntegral)
  </code></pre>
  
  <p>I don't experience the weird behavior if I do the following:</p>
  
  <ol>
  <li>Create a new directory somewhere via <code>mkdir</code></li>
  <li>Add the above <code>Main.hs</code> to the directory.</li>
  <li>Compile using <code>ghc Main.hs -O2 -rtsopts -prof</code>.</li>
  <li>Run via <code>./Main myfile.wav +RTS -hy</code>. </li>
  <li>Create the pdf using <code>hp2ps</code> and <code>ps2pdf</code>.</li>
  </ol>
  
  <p>I do experience the weird behavior if I do the following:</p>
  
  <ol>
  <li>Create a new directory, <em>laziness</em>, via <code>mkdir laziness</code>.</li>
  <li>Initiate a <code>cabal</code> project via <code>cabal init</code>.</li>
  <li>Add the above <code>Main.hs</code> to <code>/src</code>.</li>
  <li>Add <code>ghc-options: -O2 -rtsopts -prof</code> to <code>laziness.cabal</code>.</li>
  <li>Compile using <code>cabal install</code></li>
  <li>Run via <code>laziness myfile.wav +RTS -hy</code>.</li>
  <li>Create the pdf using <code>hp2ps</code> and <code>ps2pdf</code>.</li>
  </ol>
  
  <p>I even experience the weird behavior if I:</p>
  
  <ol>
  <li><code>cd laziness/src</code></li>
  <li>Compile using <code>ghc Main.hs -O2 -rtsopts -prof</code>.</li>
  <li>Run via <code>./Main myfile.wav +RTS -hy</code>. </li>
  <li>Create the pdf using <code>hp2ps</code> and <code>ps2pdf</code>.</li>
  </ol>
  
  <p>So it seems that this behavior only occurs when the code is inside a <code>cabal</code> project. This seems weird to me. Could this have something to do with the setup of my <code>cabal</code> project?.</p>