"), and then appends the answer, and catenates *that* (remembering that in the tabbed format, we separate questions and answers not with a newline, but a tab character). Finished, we let 'main' handle the I/O of printing to stdout. Whew! (In theory, this function should work on any length of text, thanks to the generality of 'onNths', but I haven't tested it with anything but the rubaiyats of Omar Khayyam.) -} permuteAndPutTogether:: [String] -> [String] permuteAndPutTogether str = map ((\x -> x ++ "\t" ++ concatQuestn str) . concatQuestn) $ onHalves hide str where concatQuestn = intercalate "

" {- | Take an answer, and hide it, so we can do Cloze deletion. ie, you could do question = [hide "First line", "Second line"]; answer = ["First line", "Second line"]. -} hide :: String -> String hide = map (\x -> if isAlphaNum x then '_' else x) {- | A highly general list function exploiting the capabilities of the List monad to generate permutations of a list such that we apply a function to all possible halves or thirds or nths. Thanks be to vixey on #haskell. -} onNths :: (Num t, Eq t) => t -> (a -> a) -> [a] -> [[a]] onNths 0 _ list = return list onNths n f (x:xs) = map (f x :) (onNths (n-1) f xs) ++ map (x :) (onNths n f xs) onNths _ _ [] = [] -- Yes, we do need to put this definition last. {- | Given a function f and the list [1,2], we'd get back [[f 1, 2], [1, f 2]]; for f [1,2,3,4], we'd get [[f 1, f 2, 3, 4], [1, 2, f 3, f 4], [f 1, 2, f 3, 4], [1, f 2, 3, f 4]]. -} onHalves :: (a -> a) -> [a] -> [[a]] onHalves f list = onNths (length list `div` 2) f list