(Apologies if my terminology is wrong).
I'm trying to write a wrapper function that handles exceptions: if the given IO
action throws, it returns Nothing
(inside an IO
context of course), but if the given IO
action succeeds, it returns Just v
.
tryMaybe :: IO a -> IO (Maybe a)
tryMaybe action = do
result <- (try action) :: IO (Either SomeException a)
return $ case result of
Left _ -> Nothing
Right v -> Just v
This results in the compiler error message:
Couldn't match type `a' with `a1'
`a' is a rigid type variable bound by
the type signature for tryMaybe :: IO a -> IO (Maybe a)
at src/Database.hs:33:13
`a1' is a rigid type variable bound by
an expression type signature: IO (Either SomeException a1)
at src/Database.hs:35:15
Expected type: IO a1
Actual type: IO a
In the first argument of `try', namely `action'
I'm guessing that the type variable a
in the first line isn't the same as the a
in the third line - they just happen to have the same name in the source code, and the compiler has renamed it a1
in the error message.
So how do I tell Haskell that these are the same types?
You need to enable the ScopedTypeVariables
extension, and the change the type signature of the top-level function to start with forall a .
:
{-# LANGUAGE ScopedTypeVariables #-}
...
tryMaybe :: forall a . IO a -> IO (Maybe a)
...
The forall
syntax brings the type variable a
into scope for the entire body of tryMaybe
, rather than it being limited to the type signature which is the default. This is mainly a historical anomaly rather than a deliberate design.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With