Programming Praxis – Permuted Index

In today’s Programming Praxis exercise we have to implement David Parnas’ permuted index system. Let’s get started.

We’re going to need some imports.

import Data.Char
import Data.List
import qualified Data.List.Key as K
import Text.Printf

We start by defining the list of stop words:

stopList :: [String]
stopList = words "a an and by for if in is of on the to"

Creating all the rotations of a line can be done with a simple list comprehension.

rot :: [String] -> [(String, String)]
rot xs = [(unwords a, unwords b) | (a, b) <- init \$
zip (inits xs) (tails xs), notElem (head b) stopList]

To print the index, we check how big the longest pre- and postfixes are and pad the others accordingly.

prettyPrint :: [(String, String)] -> IO ()
prettyPrint xs = mapM_ (\(a, b) -> printf "%*s   %-*s\n" l1 a l2 b) xs
where l1 = maximum \$ map (length . fst) xs
l2 = maximum \$ map (length . snd) xs

The only step left is to put all the rotations in the correct order.

permuteIndex :: String -> IO ()
permuteIndex = prettyPrint . K.sort (\(_, x) -> (map toLower x, x)) .
concatMap (rot . words) . lines

A quick test shows that we get the correct output:

main :: IO ()
main = permuteIndex \$ "All's well that ends well.\n" ++
"Nature abhors a vacuum.\n" ++
"Every man has a price.\n"

Making it work with files or console input is merely a matter of binding the result of readFile or getContents to permuteIndex.

One Response to “Programming Praxis – Permuted Index”

1. I. J. Kennedy Says: