11

いくつかの Haskell コードを別のマシンでコンパイルする必要がある状況があります。これらのマシンの少なくとも 1 台には、かなり古いバージョンのControl.Concurrent.STMがあり、それは不明modifyTVarです。私の現在の回避策は、modifyTVar のコードを新しいバージョンのパッケージからコピーすることです。これは、テンプレート Haskell を使用して、関数が既に定義されているかどうかを確認し、欠落している場合にのみ定義できるかどうか疑問に思いました。適切な解決策は、おそらく最新のパッケージを入手することであることは承知していますが、この状況に興味をそそられました。

4

2 に答える 2

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 [])
于 2014-06-15T21:25:07.267 に答える
3

テンプレート Haskell は、これに対してやや過剰です。CPP代わりに、MIN_VERSIONCabal が定義するマクロを使用して使用できます。

{-# LANGUAGE CPP #-}

#if MIN_VERSION_stm(2, 3, 0)
-- nothing
#else
modifyTVar = ...
#endif
于 2014-06-16T07:21:22.660 に答える