Parsec
Parsec is good for user-oriented parsers: things where you have a limited amount of input, but error messages matter. It is not very fast, but if you have small inputs, it does not matter. For example, I would choose Parsec for almost any programming language tool, because - in absolute terms - even the largest source files are not that big, but error messages really matter.
Parsec can work with different types of input data, which means that you can use it with a standard String or with a stream of tokens from external vocabulary. Since it can use String , it is great for Unicode; Built-in basic parsers, such as digit and letter , are Unicode.
Parsec also comes with a monad transformer, which means you can stack it on a monad stack. This can be useful if you want, for example, to track an additional state during your parsing. You can also use more trypsic effects, such as deterministic parsing, or something else - the usual magic of monad transformers.
Attoparsec
Attoparsec is much faster than Parsec. You should use it when you expect to get large amounts of input or performance. This is great for things like networking code (parsing the structure of packages), parsing large amounts of raw data, or working with binary file formats.
Attoparsec can work with ByteString s, which are binary data. This makes it a good choice for implementing things like binary file formats. However, since this is for binary data, it does not handle things like text encoding; for this you must use the attoparsec module for Text .
Attoparsec supports incremental parsing, which Parsec does not have. This is very important for some applications, such as network code, but not important for others.
Attorparsec has worse error messages than Parsec and sacrifices some high-level features for performance. He specializes in Text or ByteString , so you cannot use it with tokens from a custom lexer. It is also not a monad transformer.
Which one?
Ultimately, Parsec and Attoparsec satisfy completely different niches. The high-level difference is performance: if you need it, select Attoparsec; if you do not, just go with Parsec.
My usual heuristic is choosing Parsec for programming languages, configuration file formats and user input, as well as almost everything that I would otherwise have done with a regex. These are things that are usually done manually, so the parsers do not need to scale, but they need to report errors well.
On the other hand, I would choose Attoparsec for things like implementing network protocols, processing binary data and file formats, or reading large amounts of automatically generated data. Things where you are dealing with time constraints or large amounts of data that are not usually written directly by a person.
As you can see, the choice is actually often quite simple: use cases do not overlap very much. Most likely, it will be pretty clear which one to use for any particular application.