title: Conditionally binding or ignoring a value in do notation
body: <p>As a learning project I am currently trying to build a parser for the ELF file format in Haskell. Elf binary files have a section called a program header, and this header contains a word dedicated to flags. The program header contains two fields for flags: one for 64 bit flags, one for 32 bit flags, in non-sequential order.</p>
  
  <p>Like so:</p>
  
  <pre><code>data ProgramHeader =
      ProgramHeader {
          getSegmentType :: SegmentType
        , get64SegmentFlags :: SegmentFlag
        , getOffset :: Offset
        , getVirtualAddress :: Address
        , getPhysicalAddress :: Address
        , getFileSize :: Size
        , getMemorySize :: Size
        , get32SegmentFlags :: SegmentFlag
        , getAlignment :: Either Word32 Word64
      }
  </code></pre>
  
  <p>And parsing looks like this:</p>
  
  <pre><code>parseProgramHeader :: WordSize -&gt; Endianness -&gt; Get Program
  parseProgramHeader wordsize en = do
    st &lt;- parseSegmentType
    flags64 &lt;- parseSegmentFlag
    offset &lt;- parseVariant wordsize en
    virtualAddress &lt;- parseVariant wordsize en
    physicalAddress &lt;- parseVariant wordsize en
    fileSize &lt;- parseVariant wordsize en
    memorySize &lt;- parseVariant wordsize en
    flags32 &lt;- parseSegmentFlag
    a &lt;- parseVariableWord wordsize
    return $ ProgramHeader st flags64 offset virtualAddress physicalAddress fileSize memorySize flags32 a
  </code></pre>
  
  <p>Now I'd like to be able to merge those two <code>SegmentFlag</code> fields into a single one as such:</p>
  
  <pre><code>data ProgramHeader =
      ProgramHeader {
          getSegmentType :: SegmentType
        , getSegmentFlags :: SegmentFlag
        , getOffset :: Offset
        , getVirtualAddress :: Address
        , getPhysicalAddress :: Address
        , getFileSize :: Size
        , getMemorySize :: Size
        , getAlignment :: Either Word32 Word64
      }
  </code></pre>
  
  <p>But, I would still need to parse the flags word twice (in each corresponding position), keeping only the relevant one. </p>
  
  <p>My intuition is that it means I need to bind the parseSegmentFlag value only for the corresponding wordsize; while still calling parseSegmentFlag if it's not the case, but discarding the value.
  In pseudocode:</p>
  
  <pre><code>parseProgramHeader :: WordSize -&gt; Endianness -&gt; Get Program
  parseProgramHeader wordsize en = do
    st &lt;- parseSegmentType
    if wordsize == Bit64
        then
          do flags &lt;- parseSegmentFlag
        else
          discard $ parseSegmentFlag
    [...]
    if wordsize == Bit32
      then do flags &lt;- parseSegmentFlag
      else do discard $ parseSegmentFlag
  </code></pre>
  
  <p>Now I have absolutely no idea how I could perform that elegantly in Haskell. Any ideas? Pointers?</p>
  
  <p>Thanks!</p>