Различные импорты в зависимости от версии зависимостей


У меня есть модуль, который использует Control.Exception в Base < 4, который является Control.OldException в Base >= 4. Как я могу, используя cabal или любой другой инструмент, избавиться от зависимости версии (просто зависите от Base и не Base < 4) и импортировать Control.OldException при использовании Base >= 4 и Control.Exception при использовании Base < 4?

3 4

3 ответа:

cabal автоматически устанавливает определенные определения CPP на основе версии используемых пакетов.

Поэтому для вашего случая я бы:

{-# LANGUAGE CPP #-}
module Blah where
#if MIN_VERSION_base(0,4,0)
import Control.OldException
#else
import Control.Exception
#endif

Этот метод прекрасно работает с Кабалом.

(на самом деле, я бы использовал новые исключения и не стал бы утруждать себя поддержкой базы

С Cabal это делается с помощью "флагов" и алгоритма решения ограничений. Пример (из control-monad-exception на Hackage):

Flag extensibleExceptions
  description: Use extensible-exception package
  default: False

(...)

  if flag(extensibleExceptions)
    build-depends:
      extensible-exceptions >= 0.1 && <0.2,
      base >= 3.0 && <4
  else
    build-depends:
      base >= 4 && < 5

На машине с более старой версией base, Cabal попытается решить зависимость с extensibleExceptions False, потерпит неудачу, затем повторит попытку с ней True и использует другую build-depends, которая будет успешной. (Вы также можете включить флаг из команды линия.)

Http://www.haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#configurations документирует этот механизм, а остальная часть страницы описывает другие механизмы, включая прямые условные обозначения, такие как if impl(ghc >= 6.10.0).

Это языковой агностический ответ, поэтому он может не относиться к вам.

Есть пара вариантов

  1. оберните оба исключения в Суперэксцепцию, имеющую обе реализации. Дайте ему параметр, который говорит ему, какую реализацию использовать на основе Base.
  2. исключение Рефактора, являющееся дочерним элементом OldException с переопределенными вызовами. (лучший вариант)