When I mention in the type signature of the function isQuestion
the types explicitly, GHCi compiles it perfectly:
isQuestion :: [Char] -> Maybe Bool
isQuestion [] = Nothing
isQuestion xs = Just (last xs == '?')
However, when I turn to 'generic' code, it doesn't work:
isQuestion :: [a] -> Maybe b
isQuestion [] = Nothing
isQuestion xs = Just (last xs == '?')
since I get the below error:
<interactive>:138:17: error:
* Couldn't match type `b' with `Bool'
`b' is a rigid type variable bound by
the type signature for:
isQuestion :: forall a b. [a] -> Maybe b
at <interactive>:136:1-28
Expected type: Maybe b
Actual type: Maybe Bool
* In the expression: Just (last xs == '?')
In an equation for `isQuestion':
isQuestion xs = Just (last xs == '?')
* Relevant bindings include
isQuestion :: [a] -> Maybe b (bound at <interactive>:137:1)
First observation is that
last xs == something
can only work if there is a definition of (==)
in scope for the elements of xs
. But as the compiler knows nothing about a
, there is no such thing. You must narrow a
to be the subset of types with equality:
isQuestion :: Eq a => [a] -> Maybe b
The second observation is that something
is a Char
in your code ('?'
), so this method can only ever work when a ≡ Char
. Instead, you could add that something as a parameter:
isQuestion :: Eq a => a -> [a] -> Maybe b
Finally, as has been pointed out, you have a concrete return type, i.e. Maybe Bool
, as
(==) :: a -> a -> Bool
So your function's signature could be
isQuestion :: Eq a => a -> [a] -> Maybe Bool
Edited this paragraph for clarity Note that, depending on your business logic, you might not want to make a special case of the empty string. If the only thing you care about is whether a string ends with a question mark, then Nothing
and Just false
would virtually mean the same thing. In that case, your function becomes a "yes or no" question and you can drop the Maybe
:
isQuestion :: Eq a => a -> [a] -> Bool
isQuestion x = isSuffixOf [x]
or simply
isQuestion :: String -> Bool
isQuestion = isSuffixOf "?"