我可以使用模板haskell来定义缺失的函数吗?

时间:2014-06-15 19:33:47

标签: haskell template-haskell stm

我有一种情况需要在不同的机器上编译一些Haskell代码。 这些计算机中至少有一台具有Control.Concurrent.STM的旧版本,并不知道modifyTVar。我目前的解决方法是从包的newer version复制modifyTVar的代码。这让我想知道,如果可以使用模板Haskell来检查函数是否已经定义并且只定义它,如果它已经丢失了。我知道正确的解决方案可能是获得更新的包裹,但情况让我很好奇。

2 个答案:

答案 0 :(得分:8)

似乎有可能如下。首先是辅助模块:

{-# 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 [])

答案 1 :(得分:3)

模板Haskell对此有些过分 - 您可以使用CPP代替,使用Cabal将定义的MIN_VERSION宏:

{-# LANGUAGE CPP #-}

#if MIN_VERSION_stm(2, 3, 0)
-- nothing
#else
modifyTVar = ...
#endif