Search for the name of a special display function
I'm new to Haskell and I'm looking for a function name (or generally a concept name) that acts as such:
The function takes two arguments:
1. A list of elements [T]
2. A function that takes T and returns Maybe U.
The output of the function is as follows:
If all the elements in the list match some U, return Some [U].
Otherwise, return None.
i.e. if any of the displayed values are NULL then return zero, otherwise just return the displayed values.
source to share
Haskell report calls it sequence . map f
, also called mapM f
. Currently, you can call it traverse f
(GHC 7.10+).
Map and sequence
Let's think about the type of your function:
withList :: (a -> Maybe b) -> [a] -> Maybe [b]
A canonical function to map a list to another:, map
so we can use that as a starting point:
withListNotYet :: (a -> Maybe b) -> [a] -> [Maybe b]
withListNotYet f xs = map f xs
We now have a list Maybe b
, but we want to get the Maybe
outside. This is essentially what sequence
does:
sequence :: Monad m => [m a] -> m [a]
sequence [] = return []
sequence (x:xs) = do
y <- x
ys <- sequence xs
return (y : ys)
Since it Maybe
is an instance Monad
, we can use sequence
after withListNotYet
and complete our implementation for withList
:
withList f xs = sequence (map f xs)
Since this is a common operation, it has a name mapM
::
withList f xs = mapM f xs -- or withList = mapM
Traversable
During the "proposal to change bridges" , the type was mapM
changed from
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
to
mapM :: (Monad m, Traversable t) => (a -> m b) -> t a -> m (t b)
At that time, there was already a similar function called traverse
:
traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)
As you can see, the type signature is very similar. The same version of GHC that changed the type mapM
also made it a Applicative
base class Monad
, see Functor-Applicative-Monad-Proposal . So nowadays, you can usually use traverse
or mapM
. The first is a younger, more general version, and the last is an older, historical version.
And if you look at the class Traversable
, you will notice that mapM = traverse
the default.
source to share
This traverse
, defined in the class Traversable
:
traverse :: Traversable t, Applicative f => (a -> f b) -> t a -> f (t b)
your example t
has a list and f
there is Maybe
eg.
traverse (\x -> if x < 5 then Just x else Nothing) [1,2,3]
> Just [1,2,3]
traverse (\x -> if x < 5 then Just x else Nothing) [1,2,3, 9]
> Nothing
source to share
The function is called traverse
, from Data.Traversable
.
The type may surprise you at first because it is rather abstract:
traverse :: (Applicative f,Traversable t) => (a -> f b) -> t a -> f (t b)
Applicative
and Traversable
- two interfaces (type classes in Haskell terms).
-
Theses
Applicative
on the effects that we want to perform. In your case it is failing (Maybe
), but it can also fail (Either
), input / ouput (IO
), concurrent I / O (Concurrently
) and many others. -
Abstracts
Traversable
by type of container. In your case, it's a list ([]
). But other containers alsoTraversable
: final containers, which have a shape that is independent of their own values. Trees and Maps are examples. ( Presets are not an example, because their "shape" depends on their values: changing all items to the same value will reduce the size of the set.)
Traversable
is an interface for containers that support "internal iteration". These are mostly forEach
other languages. But it also provides you with a results container of the same shape as the original, which contains the converted values.
If you don't need the transformed container, the associated function traverse_
discards the result and is only executed for effects.
Function mapM
is a synonym traverse
that exists for historical reasons.
source to share
These are all really good answers. I just want to add to the board that you can find this information faster with hoogle. If you know what you are looking for, enough that you can create a type signature for your desired expression, hoogle will look for it. He's smart enough to understand type variables, etc. (I.e. It doesn't matter if you write T and U as you do, or and b as you do in Haskell).
Taking your example verbatim, [T] -> (T -> Maybe U) -> Maybe [U]
you will find among others traverse and mapM, both of which have been mentioned by other peers. Happy hoogling!
source to share
While this Data.Traverable.traverse
appears to be the correct answer, you can also implement similar functionality yourself.
isJust :: Maybe a -> Bool
isJust (Just _) = True
isJust _ = False
withList :: (a -> Maybe b) -> [a] -> Maybe [b]
withList f xs | all isJust js = Just (map (\(Just x) -> x) js)
| otherwise = Nothing
where js = map f xs
*Main> withList (\xs -> if all (<10) xs then (Just (sum xs)) else Nothing) [[1,2,3],[4,5,6],[7,8,9]]
Just [6,15,24]
*Main> withList (\xs -> if all (<9) xs then (Just (sum xs)) else Nothing) [[1,2,3],[4,5,6],[7,8,9]]
Nothing
source to share