title: Parse IP address with attoparsec
body: <p>The parser given at <a href="https://www.fpcomplete.com/school/starting-with-haskell/libraries-and-frameworks/text-manipulation/attoparsec" rel="nofollow">https://www.fpcomplete.com/school/starting-with-haskell/libraries-and-frameworks/text-manipulation/attoparsec</a> appears to work, but it has a problem.</p>
  
  <p>The code (repeated here) is:</p>
  
  <pre><code>{-# LANGUAGE OverloadedStrings #-}
  
  -- This attoparsec module is intended for parsing text that is
  -- represented using an 8-bit character set, e.g. ASCII or ISO-8859-15.
  import Data.Attoparsec.Char8
  import Data.Word
  
  -- | Type for IP's.
  data IP = IP Word8 Word8 Word8 Word8 deriving Show
  
  parseIP :: Parser IP
  parseIP = do
    d1 &lt;- decimal
    char '.'
    d2 &lt;- decimal
    char '.'
    d3 &lt;- decimal
    char '.'
    d4 &lt;- decimal
    return $ IP d1 d2 d3 d4
  
  main :: IO ()
  main = print $ parseOnly parseIP "131.45.68.123"
  </code></pre>
  
  <p>If the parser is input an invalid IP address such as "1000.1000.1000.1000", it does not fail, and returns a garbage result, due to coerced numeric conversion.</p>
  
  <p>Is there a simple way to fix this? One way is to use a larger <code>Word</code> type like <code>Word32</code> and check if the number is less than 256. However, even that probably returns garbage if the input is pathological (e.g. overflows <code>Word32</code> as well). Converting to <code>Integer</code> appears to be an option, as it is unbounded, but again, an adversarial input could make the program run out of memory.</p>
  
  <p>So what would a (hopefully elegant) parser that avoids these problems look like?</p>