i am looking for a function which takes a function (a -> a -> a) and a list of [Maybe a] and returns Maybe a. Hoogle gave me nothing useful. This looks like a pretty common pattern, so i am asking if there is a best practice for this case?
>>> f (+) [Just 3, Just 3]
Just 6
>>> f (+) [Just 3, Just 3, Nothing]
Nothing
Thanks in advance, Chris
You should first turn the [Maybe a] into a Maybe [a] with all the Just elements (yielding Nothing if any of them are Nothing).
This can be done using sequence, using Maybe's Monad instance:
GHCi> sequence [Just 1, Just 2]
Just [1,2]
GHCi> sequence [Just 1, Just 2, Nothing]
Nothing
The definition of sequence is equivalent to the following:
sequence [] = return []
sequence (m:ms) = do
x <- m
xs <- sequence ms
return (x:xs)
So we can expand the latter example as:
do x <- Just 1
xs <- do
y <- Just 2
ys <- do
z <- Nothing
zs <- return []
return (z:zs)
return (y:ys)
return (x:xs)
Using the do-notation expression of the monad laws, we can rewrite this as follows:
do x <- Just 1
y <- Just 2
z <- Nothing
return [x, y, z]
If you know how the Maybe monad works, you should now understand how sequence works to achieve the desired behaviour. :)
You can then compose this with foldr using (<$>) (from Control.Applicative; equivalently, fmap or liftM) to fold your binary function over the list:
GHCi> foldl' (+) 0 <$> sequence [Just 1, Just 2]
Just 3
Of course, you can use any fold you want, such as foldr, foldl1 etc.
As an extra, if you want the result to be Nothing when the list is empty, and thus be able to omit the zero value of the fold without worrying about errors on empty lists, then you can use this fold function:
mfoldl1' :: (MonadPlus m) => (a -> a -> a) -> [a] -> m a
mfoldl1' _ [] = mzero
mfoldl1' f (x:xs) = return $ foldl' f x xs
and similarly for foldr, foldl, etc. You'll need to import Control.Monad for this.
However, this has to be used slightly differently:
GHCi> mfoldl1' (+) =<< sequence [Just 1, Just 2]
Just 3
or
GHCi> sequence [Just 1, Just 2] >>= mfoldl1' (+)
Just 3
This is because, unlike the other folds, the result type looks like m a instead of a; it's a bind rather than a map.
As I understand it, you want to get the sum of a bunch of maybes or Nothing if any of them are Nothing. This is actually pretty simple:
maybeSum = foldl1 (liftM2 (+))
You can generalize this to something like:
f :: Monad m => (a -> a -> a) -> [m a] -> m a
f = foldl1 . liftM2
When used with the Maybe monad, f works exactly the way you want.
If you care about empty lists, you can use this version:
f :: MonadPlus m => (a -> a -> a) -> [m a] -> m a
f _ [] = mzero
f fn (x:xs) = foldl (liftM2 fn) x xs
What about something as simple as:
λ Prelude > fmap sum . sequence $ [Just 1, Just 2]
Just 3
λ Prelude > fmap sum . sequence $ [Just 1, Just 2, Nothing]
Nothing
Or, by using (+):
λ Prelude > fmap (foldr (+) 0) . sequence $ [Just 1, Just 2]
Just 3
λ Prelude > fmap (foldr (+) 0) . sequence $ [Just 1, Just 2, Nothing]
Nothing
So, maybeSum = fmap sum . sequence.
Related
I have a task in Haskell (no, it's not my homework, I'm learning for exam).
The task is:
Write point-free function numocc which counts occurrences of element in given lists. For example: numocc 1 [[1, 2], [2, 3, 2, 1, 1], [3]] = [1, 2, 0]
This is my code:
addif :: Eq a => a -> Int -> a -> Int
addif x acc y = if x == y then acc+1 else acc
count :: Eq a => a -> [a] -> Int
count = flip foldl 0 . addif
numocc :: Eq a => a -> [[a]] -> [Int]
numocc = map . count
numocc and count are 'point-free', but they are using function addif which isn't.
I have no idea how can I do the function addif point-free. Is there any way to do if statement point-free? Maybe there is a trick which use no if?
I would use the fact that you can easily convert a Bool to an Int using fromEnum:
addif x acc y = acc + fromEnum (x == y)
Now you can start applying the usual tricks to make it point-free
-- Go prefix and use $
addif x acc y = (+) acc $ fromEnum $ (==) x y
-- Swap $ for . when dropping the last argument
addif x acc = (+) acc . fromEnum . (==) x
And so on. I won't take away all the fun of making it point free, especially when there's tools to do it for you.
Alternatively, you could write a function like
count x = sum . map (fromEnum . (==) x)
Which is almost point free, and there are tricks that get you closer, although they get pretty nasty quickly:
count = fmap fmap fmap sum map . fmap fmap fmap fromEnum (==)
Here I think it actually looks nicer to use fmap instead of (.), although you could replace every fmap with (.) and it would be the exact same code. Essentially, the (fmap fmap fmap) composes a single argument and a two argument function together, if you instead give it the name .: you could write this as
count = (sum .: map) . (fromEnum .: (==))
Broken down:
> :t fmap fmap fmap sum map
Num a => (a -> b) -> [a] -> b
So it takes a function from b to a numeric a, a list of bs, and returns an a, not too bad.
> :t fmap fmap fmap fromEnum (==)
Eq a => a -> a -> Int
And this type can be written as Eq a => a -> (a -> Int), which is an important thing to note. That makes this function's return type match the input to fmap fmap fmap sum map with b ~ Int, so we can compose them to get a function of type Eq a => a -> [a] -> Int.
why not
numocc x
= map (length . filter (== x))
= map ((length .) (filter (== x)) )
= map (((length .) . filter) (== x))
= map (((length .) . filter) ((==) x))
= map (((length .) . filter . (==)) x)
= (map . ((length .) . filter . (==))) x
= (map . (length .) . filter . (==)) x
and then the trivial eta-contraction.
One trick would be to import one of the many if functions, e.g. Data.Bool.bool 1 0 (also found in Data.Bool.Extras).
A more arcane trick would be to use Foreign.Marshal.Utils.fromBool, which does exactly what you need here. Or the same thing, less arcane: fromEnum (thanks #bheklilr).
But I think the simplest trick would be to simply avoid counting yourself, and just apply the standard length function after filtering for the number.
Using the Enum instance for Bool, it is possible to build a pointfree replacement for if that can be used in more general cases:
chk :: Bool -> (a,a) -> a
chk = ([snd,fst]!!) . fromEnum
Using chk we can define a different version of addIf:
addIf' :: Eq a => a -> a -> Int -> Int
addIf' = curry (flip chk ((+1),id) . uncurry (==))
Now we can simply replace chk in addIf':
addIf :: Eq a => a -> a -> Int -> Int
addIf = curry (flip (([snd,fst]!!) . fromEnum) ((+1),id) . uncurry (==))
I think you’re looking for Data.Bool’s bool, which exists since 4.7.0.0 (2014–04–08).
incif :: (Eq a, Enum counter) => a -> a -> counter -> counter
incif = ((bool id succ) .) . (==)
The additional . allows == to take two parameters, before passing the expression to bool.
Since the order of parameters is different, you need to use incif like this:
(flip . incif)
(Integrating that into incif is left as an exercise to the reader. [Translation: It’s not trivial, and I don’t yet know how. ;])
Remember that in Haskell list comprehensions, if conditionals can be used in the result clause or at the end. But, most importantly, guards without if can be used to filter results. I am using pairs from zip. The second of the pair is the list number. It stays constant while the elements of the list are being compared to the constant (k).
Your result [1,2,0] does not include list numbers 1, 2 or 3 because it is obvious from the positions of the sums in the result list. The result here does not add the occurrences in each list but list them for each list.
nocc k ls = [ z | (y,z) <- zip ls [1..length ls], x <- y, k == x]
nocc 1 [[1, 2], [2, 3, 2, 1, 1], [3]]
[1,2,2] -- read as [1,2,0] or 1 in list 1, 2 in list 2 and 0 in list 3
I want a function that takes in a list of Maybe a, and returns Just [a] if all contents are Just a, otherwise returns Nothing.
f :: [Maybe a] -> Maybe [a]
-- f [Just x, Just y ] = Just [x, y]
-- f [Just x, Nothing] = Nothing
I think it doesn't have to be Maybe and List but any Functor Applicative or Monad, but I can't think up the way.
This is a great example of where hoogle comes in handy. It's a search engine where you can enter a type signature and get the functions that match—even if they are more polymorphic.
Entering [Maybe a] -> Maybe [a] we get a bunch of results.
The first one is:
sequence :: Monad m => [m a] -> m [a]
We can try this out in GHCi:
Prelude> let xs = [Just 1, Just 2, Just 3]
Prelude> sequence xs
Just [1,2,3]
Prelude> let xs = [Just 1, Nothing, Just 3]
Prelude> sequence xs
Nothing
Hey, look at that: exactly what we were looking for! So the function you want is sequence which also happens to work for types other than Maybe.
This is code #1:
fibs = 0:1:zipWith (+) fibs (tail fibs)
I wrote the same code with list comprehension (code #2):
fibs' = 0:1:[x+y|x<-fibs',y<-tail fibs']
but code #1 produces the Fibonnacci numbers while code #2 produces 0 1 1 1 1
Why does this happen?
List comprehensions such as [x+y|x<-fibs',y<-tail fibs'] will generate x+y for all combinations of x,y extracted from the two lists. For instance,
[ (x,y) | x<-[1..10] , y<-[1..10] ]
will generate all the 100 pairs, essentially computing the cartesian product of the two lists.
Zipping the lists instead only generates pairs for the corresponding elements, yielding only 10 pairs.
Parallel list comprehensions instead work as zip does. For instance,
[ (x,y) | x<-[1..10] | y<-[1..10] ]
will return the same 10 pairs as zip. You can enable this Haskell extension by adding {-# LANGUAGE ParallelListComp #-} at the beginning of your file.
Personally, I do not use this extension much, preferring to explicitly use zip instead.
List comprehensions over multiple lists do not work like zip/zipWith - each element of one list is combined with each element of the other list rather than being combined pair-wise. To illustrate this difference, look at this simpler example:
xs = [1,2]
ys = [3, 4]
zipped = zipWith (+) xs ys -- [4, 6]
comprehended = [x+y | x <- xs, y <- ys] [4, 5, 5, 6]
To get the behavior of zip in a list comprehension, you'd need to use the GHC extension for parallel list comprehensions, which allows you to write this:
parallelComp = [x+y | x <- xs | y <- ys] -- [4, 6]
The reason is: it's not the same code. :) The first sample uses zipWith which is applying (+) pairwise. The second one does something like Cartesian product, but instead of returning pair (x,y) it returns x+y.
Compare:
zip [1..5] [2..6] === [(1,2),(2,3),(3,4),(4,5),(5,6)]
With:
[ (x,y) | x <- [1..5], y <- [2..6] ] === [(1,2),(1,3),(1,4),(1,5),(1,6),
(2,2),(2,3),(2,4),(2,5),(2,6),
(3,2),(3,3),(3,4),(3,5),(3,6),
(4,2),(4,3),(4,4),(4,5),(4,6),
(5,2),(5,3),(5,4),(5,5),(5,6)]
The list comprehension
[ x + y | x <- xs, y <- ys ]
equals (more or less) to the following imperative pseudocode
list = emptyList
foreach (x in xs) {
foreach (y in ys) {
append (x+y) to list
}
}
return list
However, if that ys is an infinitive list, as in your code #2, then the result list will be
list = emptyList
x = head of xs
foreach (y in ys) {
append (x+y) to list
}
return list
That is why you got that list consists of 0, 1, 1, ... .
You can get the behaviour you want using ZipList rather than []. Since ZipList is not a monad you cannot use monadic do. Instead you have to use applicative do, also known as "arrow notation"! :)
{-# LANGUAGE Arrows #-}
import Prelude hiding (id, (.))
import Control.Arrow
import Control.Applicative
import Control.Category
data A f a b = A (f (a -> b))
type Arr f a = A f () a
runA :: A f a b -> f (a -> b)
runA (A f) = f
arrOfApp :: Functor f => f a -> Arr f a
arrOfApp = A . fmap const
appOfArr :: Functor f => Arr f a -> f a
appOfArr = fmap ($ ()) . runA
The definitions above are rather similar to those you can find in optparse-applicative.
zipListArr :: [a] -> Arr ZipList a
zipListArr = arrOfApp . ZipList
getZipListArr :: Arr ZipList a -> [a]
getZipListArr = getZipList . appOfArr
instance Applicative f => Category (A f) where
id = A (pure id)
A f . A g = A ((.) <$> f <*> g)
instance Applicative f => Arrow (A f) where
arr f = A (pure f)
first (A f) = A (fmap first f)
fibs' :: [Int]
fibs' = 0 : 1 : (getZipListArr $ proc () -> do
x <- zipListArr fibs' -< ()
y <- zipListArr (tail fibs') -< ()
returnA -< x + y)
*Main> take 10 fibs'
[0,1,1,2,3,5,8,13,21,34]
This is a trival question.
But what is the standard way to map a function (+1 in this example) on nested list?
map (\x -> map (+1) x) [[1,2,3],[4,5,6]]
I use the above way in my code, but what is a good way to do that? Is there something like a mapNested (+1) [[1,2,3],[4,5,6]] or similar? I used google and hoogle but got too much generic results.
There's a few ways but the most obvious is:
Prelude> map (map (+1)) [[1,2,3],[4,5,6]]
[[2,3,4],[5,6,7]]
This would be the textbook answer.
Maybe you like to do the outer part with a list comprehension?
Prelude> [ map (+1) xs | xs <- [[1,2,3],[4,5,6]] ]
[[2,3,4],[5,6,7]]
Or even the whole thing?
Prelude> [ [ x + 1 | x <- xs ] | xs <- [[1,2,3],[4,5,6]] ]
[[2,3,4],[5,6,7]]
I don't think it defined anywhere in the standard library, but you can define it as such:
mapNested :: (a -> b) -> [[a]] -> [[b]]
mapNested = map . map
Or to make it more generic (ie. work on other functors than lists):
fmapNested :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)
fmapNested = fmap . fmap
Example use:
fmapNested (+1) [Some 1, None, Some 3] -- == [Some 2, None, Some 4]
You need composition of maps: (map . map) (+1) [[1,2,3],[4,5,6]]
Is there a more idiomatic way to implement the following? I feel like I'm missing a way to get rid of the lambda, but couldn't figure out a way to convert it to point-free. Maybe there is another non-applicative way as well that is more straight forward?
import Data.Maybe
import Control.Applicative
foldl (\x y -> pure (+) <*> x <*> y) (Just 0) [Just 3, Just 4]
-- Just 7
foldl (\x y -> pure (+) <*> x <*> y) (Just 0) [Just 3, Just 4, Nothing]
-- Nothing
I'd just use sequence from Control.Monad:
> fmap sum $ sequence [Just 3, Just 4]
Just 7
> fmap sum $ sequence [Just 3, Just 4, Nothing]
Nothing
For the point-free form:
sumMaybe :: Num a => [Maybe a] -> Maybe a
sumMaybe = fmap sum . sequence
The most direct way to eliminate the lambda is to use liftA2; it's exactly the code you wrote
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 f x y = pure f <*> x <*> y
foldl (liftA2 (+)) (Just 0) [Just 1, Just 2]
then we have a few choices for how to propagate the errors. This code has it that any Nothing will lead to a total failure. We can do that in two steps like #bhekilr suggested using sequence.
sum <$> sequence [Just 1, Just 2] sum <$> sequence [Just 1, Nothing]
Just (sum [1,2]) sum <$> Nothing
Just 3 Nothing
We can also use the fact that (+) induces a Monoid on the values in order to just "ignore" Nothings. Most literally that would be
import Data.Monoid
getSum $ foldMap (maybe mempty Sum) [Just 1, Just 2, Nothing]
-- equivalent to, but faster than
getSum . mconcat . map (maybe mempty Sum) $ [Just 1, Just 2, Nothing]
getSum . mconcat $ [Sum 1, Sum 2, Sum 0]
3
But we can also use catMaybe from Data.Monoid to do it in two steps
sum . catMaybes $ [Just 1, Just 2, Nothing]
sum [1, 2]
3
I think foldM works well here.
import Control.Monad
sumMay = foldM (fmap . (+)) 0
I think it's the clearest as it maps (Ba duh duh ching) to what you'd do in pure code.
You can lift the (+) in the Maybe Monad with:
input> fold (liftM2 (+)) (Just 0) [Just 1, Just 2]
Just 3
input> fold (liftM2 (+)) (Just 0) [Just 1, Just 2, Nothing]
Nothing
import Data.Maybe
import Data.List
sumMaybes = sum . catMaybes