Question

I am trying to convert a function of maximum utilizing a foldr function to one that also incorporates the maybe type. It is originally:

maximum' :: (Ord a) => [a] -> a  
maximum' = foldr1 (\x acc -> if x > acc then x else acc)

It works perfectly with sets, but not with the empty set. I want to convert it to use maybe types instead.

My thought process was:

mymax :: (Ord a) => [Maybe a] -> Maybe a 
mymax = foldr (\(Just x) (Just b) -> if ((Just x) > (Just b)) then (Just x) else (Just b)) Nothing

It compiles with no errors and works when I give it the empty set. However, when I give it a set with numbers in it, it no longer works! Can someone point me in the right direction on how I can get the functionality of it also getting the maximum from a list of maybes?

I really want to use the foldr function in my solution....

I've now tried:

mymax :: (Ord a) => [a] ->  Maybe a 
mymax = foldr (\x b -> if x > b then (Just x) else (Just b)) Nothing 

But it will not compile:

    Couldn't match expected type `Maybe b -> Maybe a'
                with actual type `Maybe a0'
    In the return type of a call of `Just'
    Probable cause: `Just' is applied to too many arguments
    In the expression: (Just x)
    In the expression: if x > b then (Just x) else (Just b)
Failed, modules loaded: none.
Was it helpful?

Solution

If you want to do it in a single foldr, we can exploit the fact that Ord a => Ord (Maybe a), that is, any ordering on a can be extended to an ordering on Maybe a.

We also have Just x > Nothing, for all x :: Ord a => a.

mymax :: (Ord a) => [a] ->  Maybe a 
mymax = foldr (\x b -> let x' = Just x in if x' > b then x' else b) Nothing 
-- equivalently
mymax = foldr (\x b -> let x' = Just x in max x' b) Nothing 
mymax = foldr (\x' b -> max x' b) Nothing . map (\x -> Just x)
mymax = foldr max Nothing . map Just

If we want to do minimum, we'll have to do it a bit differently, since Nothing is the lower bound for the type Ord a => Maybe a, which means that foldr min Nothing . map Just == const Nothing, which isn't useful.

mymin :: (Ord a) => [a] -> Maybe a
mymin = foldr (\x b -> case b of
    Nothing -> Just x
    Just y  -> Just (min x y)
  ) Nothing
-- which is equivalent to
mymin = foldr (\x b -> Just $ case b of
    Nothing -> x
    Just y  -> min x y
  ) Nothing
mymin = foldr (\x b -> Just $ maybe x (min x) b) Nothing
mymin = foldr (\x -> Just . maybe x (min x)) Nothing

Honestly, though, I think pattern matching makes solutions a lot clearer

mymax [] = Nothing
mymax (a:as) = Just $ foldr max a as

mymin [] = Nothing
mymin (a:as) = Just $ foldr min a as

OTHER TIPS

I think you actually want mymax to have type (Ord a) => [a] -> Maybe a. Here's a potential implementation that uses pattern matching and your original maximum' function:

mymax :: (Ord a) => [a] -> Maybe a
mymax [] = Nothing
mymax xs = Just (maximum' xs)

Also, Learn You A Haskell is a great resource if you haven't already come across it!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top