Parsec for primes and fibs I decided to spend some time working with parsec. I've written some code to check for primality and for whether something is a Fibonacci number. I'm mainly hoping for feedback on readability, but if you have any performance tips I'd be interested in those as well.

import Text.Parsec
import Text.Parsec.Error
import Control.Applicative hiding ((&lt;|&gt;))

toXTerminatedAs :: Int -&gt; String
toXTerminatedAs = end . parse (manyAccum acc digit) "" . show
  where acc digit cur = concat (replicate 10 cur) ++ toAs digit
        toAs digit    = replicate (fromEnum digit - 48) 'a'
        end (Left _)  = error "I can't deal with negative numbers, sorry"
        end (Right x) = x ++ "x"

isLeft :: Either a b -&gt; Bool
isLeft (Left _) = True
isLeft _        = False

fib :: Int -&gt; Bool
fib = not . isLeft . parse (fibParser "a" "") "" . toXTerminatedAs

fibParser a b = char 'x' &lt;|&gt; (\_ -&gt; fibParser b (a++b)) =&lt;&lt; string a

prime :: Int -&gt; Bool
prime = isLeft . parse (char 'x' &lt;|&gt; primeParser "a") "" . tail . toXTerminatedAs

primeParser x = (\c -&gt; try (many1 (string (c:x)) *&gt; char 'x') &lt;|&gt; primeParser (c:x)) =&lt;&lt; char 'a'


toXTerminatedAs is pretty ugly, but I haven't been able to think of any improvements. As the name/signature implies it turns a number n into n 'a's followed by an x.

prime works for all natural numbers, but it returns True for 0, and I'm not really sure what to do about it besides hard-coding it in somewhere.
Parsers are for parsing

This is probably the strangest primality test I've ever seen. So for those that want to write their own primality test, please don't use this approach.

Almost all your functions can be written without a Parser. toXTerminatedAs is probably the best example:

toXTerminatedAs :: Int -&gt; String
toXTerminatedAs n = replicate n 'a' ++ "x"


That's easy to read, and more likely to be correct. Either way, I assume you know that, so let's get started with the actual review.

Try not to shadow existing names

We return to toXTerminatedAs:

toXTerminatedAs :: Int -&gt; String
toXTerminatedAs = end . parse (manyAccum acc digit) "" . show
  where acc digit cur = concat (replicate 10 cur) ++ toAs digit
        toAs digit    = replicate (fromEnum digit - 48) 'a'
        end (Left _)  = error "I can't deal with negative numbers, sorry"
        end (Right x) = x ++ "x"


We have three digits here. Two of them are function arguments, but the first one is Parsec's digit function. That's misleading. Use d or another name that's not already in use. Alternatively, import Parsec qualified or as P to show the difference more clearly.

Use the standard library

We stay at toXTerminatedAs. fromEnum digit - 48 isn't that clear to someone who doesn't know Enum instances or 48 well. But digitToInt shows its intend very well. It's provided by Data.Char:

import Data.Char

-- ....

toXTerminatedAs :: Int -&gt; String
toXTerminatedAs = end . parse (manyAccum acc digit) "" . show
  where acc d cur     = concat (replicate 10 cur) ++ toAs d
        toAs d        = replicate (digitToInt d) 'a'
        end (Left _)  = error "I can't deal with negative numbers, sorry"
        end (Right x) = x ++ "x"


isLeft is provided by Data.Either, so no reason to implement it yourself.

Also, try to avoid ++ in recursive functions or accumulators, as it turns \$\mathcal O(n)\$ algorithms into \$\mathcal O(n^2)\$ ones.

Encapsulate often used functionality in a function

You often use parse parser "". That's somewhat error prone as you can accidentally forget the file name.

Instead write a small function that takes care of the SourceName for you:

parse' :: Stream s Identity t =&gt; Parsec s () a -&gt; s -&gt; Either ParseError a
parse' p = parse p ""


While we're at it, we add a 

parseViaX p = isLeft . parse' p . toXTerminatedAs


Add type signatures

parseViaX is missing its type signatures because I don't know the ones of fibParser and primeParser. Always add type signatures to top-level bindings. Not only will it serve as minimal documentation, but it will also make sure that the compiler does not infer too general types or types you didn't expect.

Document complicated expressions

fibParser and primeParser should get some documentation.

Bottom line

Don't mix parsing and arithmetic, at least for arithmetic tests. It's messy and hard to read. Both fib and prime are easy to write without any parsing at all.

If you were going for code obfuscation: kudos to you, that was brilliant.