我有一种情况需要在不同的机器上编译一些Haskell代码。
这些机器中至少有一台有相当旧的版本 Control.Concurrent.STM,那不知道 modifyTVar
。我目前的解决方法是从a复制modifyTVar的代码 较新的版本 的包。这让我想知道,如果有可能使用模板Haskell来检查函数是否已经定义并且只定义它,如果它丢失了。我知道正确的解决方案可能是获得更新的软件包,但这种情况让我很好奇。
我有一种情况需要在不同的机器上编译一些Haskell代码。
这些机器中至少有一台有相当旧的版本 Control.Concurrent.STM,那不知道 modifyTVar
。我目前的解决方法是从a复制modifyTVar的代码 较新的版本 的包。这让我想知道,如果有可能使用模板Haskell来检查函数是否已经定义并且只定义它,如果它丢失了。我知道正确的解决方案可能是获得更新的软件包,但这种情况让我很好奇。
似乎有可能如下。首先是一个辅助模块:
{-# 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
并使用它作为
{-# 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
|])
缺点是它正在使用 lookupValueName
,这只是在TH的最新版本中,因此在处理旧安装时,这可能无济于事。或许可能的解决方案是打电话 reify
在给定的名称和使用 recover
处理名称缺失时的情况。
更新: 该版本使用 reify
代替 lookupValueName
作品:
-- | Add a function if it doesn't exist.
addFn :: String -> Q [Dec] -> Q [Dec]
addFn name decl = recover decl (reify (mkName name) >> return [])
模板Haskell有点矫枉过正 - 你可以使用 CPP
相反,使用 MIN_VERSION
Cabal将定义的宏:
{-# LANGUAGE CPP #-}
#if MIN_VERSION_stm(2, 3, 0)
-- nothing
#else
modifyTVar = ...
#endif