I'm learning Haskell on my own, and I'm wondering if this is idiomatic Haskell.
In particular: is it a common pattern to "wrap" the result in a list in order to make a function total? (that's what I ended up doing to ensure the function was total and no compiler warnings about not matching a pattern).
safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:_) = Just x
firstLetters :: [String] -> [Char]
firstLetters ss = concat $
map (\s -> case safeHead s of
Nothing -> []
Just c -> [c]) ss
2 Answers 2
Well a few thoughts, of all String = [Char]
so we could really give the signature
firstLetters :: [String] -> String
Whether you think this is better is a matter of taste. Second, you should take a look at
Data.Maybe.mapMaybe :: (a -> Maybe b) -> [a] -> [b]
It's exactly what you'd expect, it applies a function to Maybe
s and prunes out the Nothing
s. This simplifies the slightly ugly concat
bit.
firstLetters = mapMaybe safeHead
Much clearer :) In the interest of teaching you to fish, here's how I found the name of mapMaybe
-
\$\begingroup\$ When you say "is a matter of taste" is that a 50/50 divide in the Haskell community, or more like a 90/10 towards using String? \$\endgroup\$j-a– j-a2014年11月20日 05:24:03 +00:00Commented Nov 20, 2014 at 5:24
-
\$\begingroup\$ @j-a 50/50. In general you should prefer
String
when you're using well strings. In all other cases it's entirely up to you! \$\endgroup\$daniel gratzer– daniel gratzer2014年11月20日 06:02:46 +00:00Commented Nov 20, 2014 at 6:02
In addition to @jozefg's answer, Data.Maybe
also contains listToMaybe
.
listToMaybe :: [a] -> Maybe a
The
listToMaybe
function returnsNothing
on an empty list orJust a
wherea
is the first element of the list.
Which reduces the code to
firstLetters = mapMaybe listToMaybe