I recently started writing my first application at work in Haskell and it deals with a lot of parsing.<br>Among other things I often have to check for a lot of alternatives for fixed strings (parsing natural<br>language text and people have a lot of ways to abbreviate the same thing in labels). So far I have been<br>


doing this basically via<br><br>choice $ map (try . string) [ &quot;foo&quot;, &quot;bar&quot;, ... ]<br><br>This works fine but has two disadvantages, it isn&#39;t very fast, in particular when many of the strings<br>start with the same prefix and it also is a bit error prone since it breaks when you place a prefix of<br>


another string earlier in the list.<br><br>My attempt at a solution was to use the bytestring-trie package for a little utility function that basically<br>parses one character at a time, checks if the string parsed so far is in the trie and then calls itself recursively<br>


with the trie starting with that string. My attempt at that so far looks like this:<br><br>(dependencies bytestring-trie, utf8-string and parsec 3)<br><br>import qualified Data.ByteString.UTF8 as UTF8<br>import qualified Data.Trie as Trie<br>


import Text.Parsec<br>import Text.Parsec.Text (GenParser)<br><br>anyOf :: [String] -&gt; GenParser u String<br>anyOf l =<br>  try $ anyOf&#39; t &quot;&quot;<br>    where t = Trie.fromList $ zip (map UTF8.fromString l) (repeat ())<br>


          anyOf&#39; :: Trie.Trie () -&gt; String -&gt; GenParser u String<br>          anyOf&#39; t s = try $ do<br>              c &lt;- lookAhead $ anyChar<br>              let newS = s ++ [ c ] in<br>                case Trie.submap (UTF8.fromString newS) t of<br>


                  emptyT | Trie.null emptyT -&gt;<br>                    case Trie.member (UTF8.fromString s) t of<br>                      True -&gt;<br>                        return s<br>                      False -&gt;<br>


                        unexpected $ show newS++&quot;, expecting one of &quot;++show l<br>                  restT -&gt; do<br>                    _ &lt;- anyChar<br>                    try $ anyOf&#39; restT newS<br><br>


A successful example usage would be:<br><br>parseTest (do; r1 &lt;- anyOf [&quot;Hello&quot;, &quot;Hallo&quot;, &quot;Foo&quot;, &quot;HallofFame&quot;]; r2 &lt;- string &quot;bla&quot;; return (r1, r2)) &quot;Hallobla&quot;<br>


<br>which results in<br><br>(&quot;Hallo&quot;,&quot;bla&quot;)<br><br>(the extra string parser is there so errors in parsing too much are not hidden). An error would result .e.g. from<br><br>parseTest (do; r1 &lt;- anyOf [&quot;Hello&quot;, &quot;Hallo&quot;, &quot;Foo&quot;, &quot;HallofFame&quot;]; r2 &lt;- string &quot;bla&quot;; return (r1, r2)) &quot;Hallofbla&quot;<br>


<br>which prints this:<br><br>parse error at (line 1, column 8):unknown parse error<br><br>And my question about this is made up of two parts<br><br>1. Why doesn&#39;t it print my &quot;unexpected&quot; message but instead says unknown parse error<br>


2. Why is the location in the text off (I would expect it to fail at 
column 6 (first character beyond the result it could return) or 7 (first
 character that makes the string no prefix of any acceptable string)<br><br>I
 am afraid my knowledge of Parsec internals is a bit too limited, some 
Google queries showed no similar problems and no obvious places in the 
Parsec source code to check for the answer to the first question in 
particular and I suspect the second is closely related to the first.<br>
<br>Thanks for reading through my question and I hope someone knows the answer or at least some clues on where i might find it.<br><br>Matthias Hoermann<br><br>P.S.: I am hoping this time this works, last time it was rejected because google sends with @<a href="http://googlemail.com">googlemail.com</a> instead of @<a href="http://gmail.com">gmail.com</a> for some reason.<br>