Haskell URL query string encoder and parser

Haskell
import Data.Char (chr, digitToInt, ord)
import Data.List (intercalate)
import Text.Printf (printf)

urlEncode :: String -> String
urlEncode = concatMap esc
  where
    esc c | c `elem` keep = [c]
          | otherwise = printf "%%%02x" (ord c)
    keep = ['A' .. 'Z'] ++ ['a' .. 'z'] ++ ['0' .. '9'] ++ "-_.~"

renderQuery :: [(String, String)] -> String
renderQuery = intercalate "&" . map (\(k, v) -> urlEncode k ++ "=" ++ urlEncode v)

parseQuery :: String -> [(String, String)]
parseQuery = map pair . filter (not . null) . splitOn '&'
  where
    pair kv = let (k, v) = break (== '=') kv in (decode k, decode (drop 1 v))
    splitOn sep s = case break (== sep) s of
      (a, []) -> [a]
      (a, _ : rest) -> a : splitOn sep rest
    decode [] = []
    decode ('%' : a : b : rest) = chr (digitToInt a * 16 + digitToInt b) : decode rest
    decode (c : rest) = c : decode rest