Couple of things:
`fromJust` is a code smell. In general, you should at least consider replacing it with `fromMaybe (error msg)` where `msg` is a more useful error message than '*** Exception: Maybe.fromJust: Nothing'.
Of course in this particular case, that will never come up because you can prove that `y` is never Nothing using the guard condition. But in that case, it's better practice to use pattern matching and let the compiler prove it for you:
select p y ~(xs,ys) = acc $ p y
where
acc (Just x) = (x:xs, ys)
acc Nothing = ( xs, y:ys)
The `partitionMaybe` function looks a bit odd to me. The computation you're trying to express is 'If this computation succedes, return whatever value it returned, but if it fails return some default value'. This is not a natural use of the Maybe data type: that's what Either is for. There's even a `partitionEithers` library function. `lookup` returns Maybe, not Either, but we can fix that.
Here's my go (I've changed around the API a little bit as well)
toEither :: a -> (Maybe b) -> Either a b
toEither _ (Just x) = Right x
toEither y Nothing = Left y
lookupEither :: Eq a => a -> [(a,b)] -> Either a b
lookupEither key assocs = toEither key $ lookup key assocs
uppercase :: String -> String
uppercase = map toUpper
extract :: [String] -> [(String,b)] -> ([String],[b])
extract xs assocs =
let xs' = map uppercase xs
eithers = map (\x -> lookupEither x assocs) xs'
-- spoilers: same as [ lookupEither x assocs | x <- xs' ]
in partitionEithers eithers
main :: IO ()
main = print $ extract ["Foo", "Bar"] [("FOO",1), ("BAZ",2)]
This differs slightly from your algorithm in that it returns '(["BAR"],[1]), where yours would return (["Bar"],[1]). If preserving the original case in the output, I would either write a `caseInsensitiveLookup` function, or use a case insensitive text data type.