encoding包在其构建脚本中使用HaXml(在Setup.hs
中)。碰巧使用在HaXml-1.19和HaXml-1.22之间改变的接口位。如果编码包能够使用任一版本构建,那将是很好的。我尝试使用通常的Cabal技巧,即做类似
{-# LANGUAGE CPP #-}
#if MIN_VERSION_HaXml(1,22,0)
-- HaXml-1.22 code
#else
-- HaXml-1.19 code
#endif
...但是在配置包之前,魔术定义不存在,并且正在构建此文件以使配置步骤成为可能。我有什么选择?有没有办法更改cabal-install调用编译Setup.hs
的命令?是否有其他机制可以有条件地选择回避阴谋的代码?
答案 0 :(得分:4)
Data.Data
接口能够(仅约!)构造和解构可能存在或不存在的类型的值。不幸的是,HaXml似乎没有Data
个类型的实例,你不能定义一个,因为你不能引用可能存在或不存在的类型,所以我们不得不求助于模板Haskell :
以下模块导出qnameCompat
:
{-# LANGUAGE TemplateHaskell #-}
module HaXmlCompat (qnameCompat) where
import Language.Haskell.TH
qnameCompat :: Q [Dec]
qnameCompat = do
mi <- maybeReify "N"
case mi of
Nothing -> sequence [
tySynD (mkName "QName") [] [t| String |],
valD [p| toQName |] (normalB [| id |]) [],
valD [p| fromQName |] (normalB [| Just |]) []]
Just (DataConI n _ _ _) -> do
s <- newName "s"
sequence [
valD [p| toQName |] (normalB (conE n)) [],
funD (mkName "fromQName") [
clause [conP n [varP s]] (normalB (appE [| Just |] (varE s))) [],
clause [ [p| _ |] ] (normalB [| Nothing |]) []]]
Just i -> fail $
"N exists, but isn't the sort of thing I expected: " ++ show i
maybeReify :: String -> Q (Maybe Info)
maybeReify = recover (return Nothing) . fmap Just . reify . mkName
使用Template Haskell在顶层拼接时,qnameCompat
会检查N
是否存在。如果是,则生成以下代码:
toQName = N
fromQName (N s) = Just s
fromQName _ = Nothing
如果没有,则产生以下内容:
type QName = String
toQName = id
fromQName = Just
现在您可以创建和解构Element
,例如使用ViewPatterns扩展程序:
myElt :: String -> Element i
myElt = Elem (toQName "elemName") [] []
eltName :: Element i -> String
eltName (Elem (fromQName -> Just n) _ _) = n
ViewPatterns很方便,但当然不是必需的:在fromQName
的结果上使用普通模式匹配也可以。
(这些想法促使我开发了notcpp package,其中包括maybeReify
和其他一些有用的实用程序)
答案 1 :(得分:2)
在cabal-install/Distribution/Client/SetupWrapper.hs
控制Setup.hs
的编译中似乎没有很多旋钮,所以你最好的选择是创建一个执行版本测试的存根Setup.hs文件,然后,一旦弄清楚版本是什么,就交给真正的Setup.hs
。
另一个技巧是创建一个兼容性填充库,安装脚本使用该库,它具有相应的版本技巧。
但也许真正的问题是:为什么Setup.hs
使用外部库?