2012-04-21 1 views
10

В пакете encoding в его сценарии построения используется Setup.hs. Случается, что биты интерфейса изменяются между HaXml-1.19 и HaXml-1.22. Было бы неплохо, если бы пакет кодировки мог строить с любой версией. Я попытался с помощью обычного Cabal трюка, а именно, делать что-то вродеИзменение способа установки Setup.hs

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

... но магия определяет не могут существовать до того, как пакет настроен, и этот файл строятся, чтобы сделать шаг конфигурирования возможно. Какие у меня варианты? Есть ли способ изменить команду, которая вызывает вызовы для компиляции Setup.hs? Есть ли еще один механизм условного выбора кода, который обойдется в кабале?

+0

Насколько серьезны изменения в интерфейсе? Каковы изменения? Возможно, шаблон haskell может спасти вас, в зависимости от того, что они собой представляют. –

+0

@benmachine Единственное реальное изменение заключается в том, что конструктор 'Element' теперь принимает значение типа' data QName = N String | SomethingIDon'tCareAbout' вместо 'String'. Файл 'Setup.hs' использует конструктор' Element' как функцию (всегда с литералом 'String') и для сопоставления шаблонов (иногда с литералом' String' и иногда с шаблоном переменной catch-all). –

+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) –

ответ

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 

Когда сращены на верхнем уровне с использованием шаблона 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 и некоторые другие полезные утилиты)

+0

Это выглядит великолепно. –

2

Там, кажется, не очень много кнопок в cabal-install/Distribution/Client/SetupWrapper.hs управления сборником Setup.hs, поэтому лучше может быть, чтобы создать стаб Setup.hs файл, который выполняет проверку версии, а затем руки прочь к реальным Setup.hs раз он выяснил, что такое версия.

Другой трюк заключается в том, чтобы создать библиотеку совместимости, которую использует ваш сценарий установки, который имеет соответствующие трюки версии.

Но, может быть, настоящий вопрос задать, вот почему: Setup.hs с использованием внешних библиотек?

+0

Хм, как будет передаваться помощь ? Разве он все равно не попытается построить (обе) вещь (я), с которой я передаю? –

+0

Правильно, вам нужно повторно выявить GHC с соответствующими определениями макросов. –