Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monoid mempty in pattern matching

I tried to write a generalized maximum function similar to the one in Prelude. My first naiv approach looked like this:
maximum' :: (F.Foldable a, Ord b) => a b -> Maybe b
maximum' mempty = Nothing
maximum' xs = Just $ F.foldl1 max xs

However, when I test it it always returns Nothing regardless of the input:
> maximum' [1,2,3]
> Nothing

Now I wonder whether it's possible to obtain the empty value of a Monoid type instance. A test function I wrote works correctly:
getMempty :: (Monoid a) => a -> a
getMempty _ = mempty

> getMempty [1,2,3]
> []

I had already a look at these two questions but I didn't figure out how the answers solve my problem:
Write a Maximum Monoid using Maybe in Haskell
Haskell Pattern Matching on the Empty Set

How would I rewrite the maximum' function to get it to work ?

like image 493
mmh Avatar asked Aug 31 '12 13:08

mmh


1 Answers

As C. A. McCann points out in his comment, you can't pattern match on values, only patterns.

The equation maximum' mempty = Nothing is actually equivalent to the equation maximum' x = Nothing. The argument gets bound to a name and Nothing is returned.

Here's a way to make your code work:

maximum' :: (F.Foldable a, Ord b, Eq (a b), Monoid (a b)) => a b -> Maybe b
maximum' xs
  | xs == mempty = Nothing
  | otherwise    = Just $ F.foldl1 max xs

I.e. you can compare the value xs against mempty. Note that we need a Monoid constraint to be able to get at the value mempty :: a b and an Eq constraint to be able to compare as well.

An other, more elegant, solution would be to use a fold to differentiate between the empty and non-empty cases:

maximum'' :: (F.Foldable a, Ord b) => a b -> Maybe b
maximum'' xs = F.foldl max' Nothing xs
  where max' Nothing x = Just x
        max' (Just y) x = Just $ max x y
like image 90
opqdonut Avatar answered Oct 04 '22 19:10

opqdonut