2012-04-21 69 views
10

encoding程序包在其构建脚本(Setup.hs)中使用HaXml。恰好使用在HaXml-1.19和HaXml-1.22之间改变的接口位。如果编码包能够用任一版本构建,那将会很好。我试着用通常的伎俩惊天动地,即做这样的事情更改Setup.hs的构建方法

{-# LANGUAGE CPP #-} 
#if MIN_VERSION_HaXml(1,22,0) 
-- HaXml-1.22 code 
#else 
-- HaXml-1.19 code 
#endif 

...但在配置软件包之前不能存在的魔法定义,并将该文件正在修建,使配置阶段可能。我有什么选择?有没有办法改变命令cabal安装调用编译Setup.hs?有没有另外一种机制来有条件地选择可以避开cabal的代码?

+0

的严重程度如何界面的变化?他们有什么样的改变?模板haskell可能可以帮助你解决问题,具体取决于它们是什么。 – 2012-04-24 21:02:04

+0

@benmachine唯一真正的变化是'Element'构造函数现在接受一个'data QName = N String | Somethingon'tCareAbout'而不是'String'。 'Setup.hs'文件使用'Element'构造函数作为一个函数(总是使用字面值'String')和模式匹配(有时使用字面值'String',有时使用全部变量模式)。 – 2012-04-24 21:36:46

+0

所以,如果你有函数'toQName'和'fromQName'就足够了,这样当'QName'存在时'toQName = N'和'fromQName'就把'N s'变成'Just s'(而其他任何东西变成'Nothing '),而当'QName'不存在时,'toQName = id'和'fromQName = Just'?那么你可以用视图模式做你想做的事情?我认为'toQName'和'fromQName'可以用模板haskell定义,使用类似于我的[notcpp软件包](http://hackage.haskell.org/package/notcpp) – 2012-04-25 09:57:07

回答

4

Data.Data接口能够(只是!)构造和解构可能存在或可能不存在的类型的值。不幸的是,HaXml似乎没有Data实例的类型,并且您不能定义一个实例,因为您不能引用可能存在或可能不存在的类型,所以我们必须求助于模板哈斯克尔:

以下模块出口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 

当使用模板哈斯克尔顶级拼接,qnameCompat会检查是否存在N。如果是的话,它会产生下面的代码:

toQName = N 
fromQName (N s) = Just s 
fromQName _ = Nothing 

如果没有,将产生以下:

type QName = String 
toQName = id 
fromQName = Just 

现在你可以创建和解构Element S,例如使用ViewPatterns扩展:

myElt :: String -> Element i 
myElt = Elem (toQName "elemName") [] [] 

eltName :: Element i -> String 
eltName (Elem (fromQName -> Just n) _ _) = n 

ViewPatterns是方便,但不是必需的,当然是:使用上的fromQName结果普通模式匹配将工作一样好。

(这些想法是什么导致我开发notcpp package,其中包括maybeReify和其他一些有用的工具)

+0

这看起来不错。 – 2012-04-25 17:38:28

2

目前似乎并没有被很多旋钮在cabal-install/Distribution/Client/SetupWrapper.hs控制Setup.hs编译,所以你最好的选择可能是创建执行版本测试,然后把手拿开到真正Setup.hs一次存根Setup.hs文件它已经找出了版本是什么。

另一个诀窍是制作安装脚本使用的具有适当版本技巧的兼容性垫片库。

但也许真正的问题是这样的:为什么Setup.hs使用外部库?

+0

的想法。嗯,如何交付帮助?难道它不会试图建立(两者)我交给的东西吗? – 2012-04-23 16:37:23

+0

对,您需要用适当的宏定义重新激活GHC。 – 2012-04-23 17:55:10