What is fmap doing here without explicitly declaring the method?
One exercise in the real world of Haskell, ch. 24, will ask to introduce a shell of rigor around Control.Concurrent.MVar
. I'm doing this, as suggested in the book, with a shell newtype
MVarS
, to guarantee that evaluate
applies to all the arguments passed to functions such as newMVar
and putMVar
.
Now one of the functions for wrapping is mkWeakMVar
, which type is MVar a -> IO () -> IO (Weak (MVar a))
. Assuming my constructors MVarS
implement strictness, I figured that for mkWeakMVar
just putting s MVarS
instead of my own MVar
. So I wrote the following:
import Control.Concurrent.MVar
import System.Mem.Weak
instance Functor Weak
newtype MVarS a = MVarS (MVar a)
mkWeakMVarS :: MVarS a -> IO () -> IO (Weak (MVarS a))
mkWeakMVarS (MVarS mv) x = (fmap . fmap) MVarS (mkWeakMVar mv x)
This works, although GHCi warns that Functor Weak
there is no explicit method declaration for fmap
. But this intrigued me. What does fmap
work in this case?
source to share
While the above code will validate, GHC will crash when trying to evaluate a value that requires a call to a missing implementation fmap
. It will look something like this:
*** Exception: /Users/tel/tmp/SO.hs:31:10-18:
No instance nor default method for class operation GHC.Base.fmap
Since this is a fairly catastrophic and completely preventable runtime error, it should serve as proof of importance -Wall
.
source to share