Determine whether input-output pairs represent something that could be a proper math function
Your monadic helper functions are all one-offs and even if they were well-named (no worries, naming just gets harder as you get more experienced, there's a reason Adam was told to do it), I'd still think it better to inline them. Then the main ends up cluttered with pointfreed binds and I turned that into a do block.

(I did reorder the monadic effects a little, moving the output of each answer in front of the reading of the next question, but I found that sacrifice worthy.)

I'm not sure you need to try your hand at error-handling in tuplefy - a badly formated input file should be as likely to have a typo in its number of words in a line as in its stated number of pairs in a function.

listToMultiMap - (k, v) is no different from the other elements of vs, so you could go listToMultiMap = toMap M.empty. toMap is folding left, bad style. You can fold right like:

toMap [] = []
toMap ((k0, v0):ys) = case M.lookup k0 m of
  Nothing  -&gt; M.insert k0 [v0]     $ toMap ys
  Just v0s -&gt; M.insert k0 (v0:v0s) $ toMap ys


and won't need to carry a parameter into the recursive calls. And of course this can be written in terms of foldr:

listToMultiMap = foldr foo M.empty where
  foo (k0, v0) m = case M.lookup k0 m of
    Nothing  -&gt; M.insert k0 [v0]     m
    Just v0s -&gt; M.insert k0 (v0:v0s) m


And we could reduce the duplication in the last two lines there, but then again this whole thing is already handled by Data.Maps fromListWith.

import System.IO (readLn, getLine)
import Control.Monad (replicateM)
import qualified Data.Map.Strict as M
import Data.Bool (bool)

noDuplicates :: Ord a =&gt; [a] -&gt; Bool
noDuplicates = all (==1) . M.fromListWith (+) . map (,1)
--           = all ((==1) . length) . M.fromListWith (++) . map (,["Why are you looking at the ordinate?"])
--           = and . M.fromListWith (\_ _ -&gt; False) . map (,True)

main :: IO ()
main = do
  functioncount &lt;- readLn
  replicateM functioncount $ do
    paircount &lt;- readLn
    abscissae &lt;- replicateM paircount $ read . head . words &lt;$&gt; getLine
    putStrLn $ bool "NO" "YES" $ noDuplicates abscissae


It is unfortunate for pointfreedom that the first parameter of replicateM indeed should be Int.  There must be a better way than flip. Perhaps a new infix operator, semantically id, that has highest precedence to the left, and lowest to the right, to simulate enclosing brackets around its entire right side and disappearing?