One of the exercises in Real World Haskell, ch. 24, asks to implement a strictness wrapper around Control.Concurrent.MVar
. I am doing this, as suggested in the book, by using a newtype
MVarS
wrapper to ensure that evaluate
is applied to whatever arguments get passed to functions such as newMVar
and putMVar
.
Now, one of the functions to wrap is mkWeakMVar
, whose type is MVar a -> IO () -> IO (Weak (MVar a))
. Assuming that my MVarS
builder functions implement strictness, I reasoned that for mkWeakMVar
it would suffice to put MVarS
in place of its MVar
s. 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 appears to work, even though GHCi warns that there is no explicit method declaration of fmap
for Functor Weak
. But it leaves me intrigued. What makes fmap
work in this case?
While the above code will typecheck, GHC will crash when attempting to evaluate a value which requires calling upon the missing fmap
implementation. It'll look a bit like:
*** Exception: /Users/tel/tmp/SO.hs:31:10-18:
No instance nor default method for class operation GHC.Base.fmap
Since this is a rather catastrophic and entirely avoidable runtime error it ought to serve as a testament to the importance of -Wall
.