如何以向后兼容的方式为模块启用Safe Haskell

时间:2012-06-23 16:54:19

标签: haskell backwards-compatibility cabal

假设您有一个您知道安全的模块。

您希望将模块本身中的{-# LANGUAGE Safe #-}标记为Safe Haskell,或者在cabal文件中使用Extensions: Safe之类的标记。不幸的是,这些中的任何一个都会破坏向后兼容性(即模块不会建立在GHC< 7.2上)。

如果整个库都是安全的,您可以将extensions指令包装在cabal文件中,如下所示:

if impl(ghc >= 7.2)
  Extensions: Safe

但这只适用于整个图书馆。

如何以向后兼容的方式将单个模块标记为安全Haskell?

2 个答案:

答案 0 :(得分:5)

如果您不需要支持早于6.12的GHC版本(6.12.3是我使用¹测试过的最早的版本),您可以使用预处理器来完成,

{-# LANGUAGE CPP #-}
#if __GLASGOW_HASKELL__ >= 702
{-# LANGUAGE Safe #-}
#endif

或者,您可以使用.cabal文件中的标志来选择要包含的源文件。

¹对于ghc-6.12,您必须在{-# LANGUAGE #-}之前的#if之前保护所有#if个编译区,自7.0以来,它们也可能出现在{#if之后1}}。

答案 1 :(得分:2)

您可以编写两个版本的模块,并在编译时选择它们。例如:

-- has-safe/Foo.hs
{-# LANGUAGE CPP #-}
foo = 3

-- no-safe/Foo.hs
{-# LANGUAGE CPP, Safe #-}
foo = 3

-- foo.cabal
if impl(ghc >= 7)
    hs-source-dirs: has-safe
else
    hs-source-dirs: no-safe

与基于CPP的方法相比,这种方法有优点和缺点。主要优点是您可以使用cabal支持的所有条件进行选择。主要的缺点是你现在有两个文件要保持同步。 (但是,这应该特别容易自动化:类似

echo {-# LANGUAGE Safe #-} > has-safe/Foo.hs
cat no-safe/Foo.hs >> has-safe/Foo.hs

每次编辑no-safe/Foo.hs之后都应该做到这一点并且可以通过各种方式实现自动化。)