I've got a situation where I need to compile some Haskell code on different machines.
At least one of these machines has a rather old version of Control.Concurrent.STM, that doesn't know modifyTVar
. My current workaround is to copy the code for modifyTVar from a newer version of the package. This got me wondering, if it would be possible to use template Haskell to check if a function is already defined and only define it, if it's missing. I'm aware that the proper solution would probably be to get more recent packages, but the situation got me curious.
It seems to be possible as follows. First a helper module:
{-# LANGUAGE TemplateHaskell #-}
module AddFn where
import Language.Haskell.TH
-- | Add a function if it doesn't exist.
addFn :: String -> Q [Dec] -> Q [Dec]
addFn name decl = do
r <- lookupValueName name
case r of
Just l -> return []
Nothing -> report False ("adding missing " ++ name) >> decl
and use it as in
{-# LANGUAGE TemplateHaskell #-}
module Main where
import AddFn
import qualified Data.Traversable as T
$(addFn "mapM"
[d| mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]
mapM = T.mapM
|])
$(addFn "mapM1"
[d| mapM1 :: (Monad m) => (a -> m b) -> [a] -> m [b]
mapM1 = T.mapM
|])
The drawback is that it's using lookupValueName
, which is only in the recent versions of TH, so when dealing with old installations, this probably won't help. Perhaps a possible solution would be to instead call reify
on a given name, and use recover
to handle the case when the name is missing.
Update: The version using reify
instead of lookupValueName
works:
-- | Add a function if it doesn't exist.
addFn :: String -> Q [Dec] -> Q [Dec]
addFn name decl = recover decl (reify (mkName name) >> return [])
Template Haskell is somewhat overkill for this - you can use CPP
instead, using the MIN_VERSION
macros that Cabal will define:
{-# LANGUAGE CPP #-}
#if MIN_VERSION_stm(2, 3, 0)
-- nothing
#else
modifyTVar = ...
#endif
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