Haskell searching through a large textfile efficiently I have been given a list xs and a function f, and I want to know stuff like how many x &lt;- xs satisfy (f x) `elem` xs or which ones do, etc. However, the problem is that the list xs is available only as an external file.

import Data.Char
import System.IO.Strict
import qualified Data.Set as Set

vowel x = elem x "aeiou"

toPigLatin :: String -&gt; String
toPigLatin word
    | vowel (head word) = word ++ "ay"
    | not $ null [x | x &lt;- word, vowel x] = let (v, c) = span (not.vowel) word in c ++ v ++ "ay"
    | otherwise = word


wordList = lines &lt;$&gt;  System.IO.Strict.readFile "toyWordSet"
wordSet = Set.fromList &lt;$&gt; wordList

good :: String -&gt; IO Bool
good word = (Set.member (toPigLatin word)) &lt;$&gt; wordSet

mapMBool :: (a -&gt; IO b) -&gt; [a] -&gt; IO [b]
mapMBool f l = do
                case l of
                    [] -&gt; return []
                    (x:xs) -&gt; do
                            b1 &lt;- f x
                            bs &lt;- mapMBool f xs
                            return (b1:bs)  


Ultimately, I want to compute wordList &gt;&gt;= mapMBool good, which is a value of type IO [Bool] which have True at the positions where the desired property is satisfied.

Now, I have three main concerns:


When I run my code with a toyWordSet, it runs fine but I ultimately intend to replace it with /usr/share/dict/words, on which my PC freezes. How do I make my program more efficient?
Writing a function like mapMBool is not the most elegant idea ever. How can I do this more elegantly?
For some reason, I get some strange exceptions, when I try to use the lazy readFile instead of the strict version. What is happening? Why must I use strictness?


Other general comments on the coding style or practice is also welcome.
I think you've missed the forest for the trees. While the origin of your list might be IO, there's no need to carry values around inside the IO monad just because that's where you found them.

Write your functions as though the external world doesn't exist. E.g.—

-- Was `good`
pigExists :: String -&gt; Set String -&gt; Bool
pigExists word set = Set.member (toPigLatin word) set


Write your actions to set up the values you need to use your IO-ignorant functions. E.g.—

main :: IO ()
main = do
    allWords &lt;- words &lt;$&gt; readFile "wherever" -- equivalent to `allWords &lt;- wordList`
    let pigHits = map (\word -&gt; pigExists word (Set.fromList allWords)) allWords
    print $ length $ filter id pigHits -- Or some other IO action that does what you need


When in doubt, parameterize. You tripped yourself up by defining wordSet directly on wordList instead of just accepting any [String] value you're passed.