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
和其他一些有用的工具)
的严重程度如何界面的变化?他们有什么样的改变?模板haskell可能可以帮助你解决问题,具体取决于它们是什么。 – 2012-04-24 21:02:04
@benmachine唯一真正的变化是'Element'构造函数现在接受一个'data QName = N String | Somethingon'tCareAbout'而不是'String'。 'Setup.hs'文件使用'Element'构造函数作为一个函数(总是使用字面值'String')和模式匹配(有时使用字面值'String',有时使用全部变量模式)。 – 2012-04-24 21:36:46
所以,如果你有函数'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