Search code examples
haskell

Using Maybe [String] at Haskell


I want to return a string using Maybe [String], but I can't manage to do it using Maybe.

Should I define an instance?

data Contacto = Casa Integer
              | Trab Integer
              | Tlm Integer
              | Email String
              deriving (Show)
type Nome = String
type Agenda = [(Nome, [Contacto])]

addEmail :: Nome -> String -> Agenda -> Agenda
addEmail n email agenda = (n, [Email email]):(agenda)


verEmails :: Nome -> Agenda -> [String]
verEmails n [] = []
verEmails n ((nome, ((Email e):ls)):xs) = if n == nome then (e:(verEmails n xs))
                                                       else (verEmails n xs)

Here is the same function verEmails, where I use Maybe:

verEmails :: Nome -> Agenda -> Maybe [String]
verEmails n [] = Nothing
verEmails n ((nome, ((Email e):ls)):xs) = if n == nome then Just (e:(verEmails n xs))
                                                       else (verEmails n xs)

The error that GHCi gives me:

Couldn't match expected type `[String]'
                with actual type `Maybe [String]'
    In the return type of a call of `verEmails'
    In the second argument of `(:)', namely `(verEmails n xs)'
    In the first argument of `Just', namely `(e : (verEmails n xs))'

Solution

  • The problem comes from trying to do e : verEmails n xs, since verEmails n xs does not return a list, but a list enclosed in Maybe. The easiest way to handle this is to use the Data.Maybe.fromMaybe function:

    fromMaybe :: a -> Maybe a -> a
    fromMaybe onNothing Nothing = onNothing
    fromMaybe onNothing (Just a) = a
    

    Here I'm presuming you would want to return Just aList where aList contains all the emails filtered from the Agenda passed in. This means that the only way verEmails will return Nothing is when the agenda passed in is empty. So we have

    verEmails n [] = Nothing
    verEmails n ((nome, ((Email e):ls)):xs)
        = if n == nome
            then Just $ e : (fromMaybe [] $ verEmails n xs)
            else verEmails n xs
    

    This just simply converts verEmails n xs from Maybe [String] to [String], defaulting to the empty list, prepends e, then wraps it back up in a Just.

    As a side note, your function does not cover all possible cases, what happens if I were to run verEmails n ((nome, []):xs)? Or even verEmails n ((nome, [Casa 1]):xs)?