想象一下有一个新类型声明:
newtype T = T Int
此声明位于模块中但未导出。我想将类型T的值传递给函数。现在,我可以使用完全相同的定义声明我自己的T版本。如果我将(my.T 0)
传递给期望(hidden.T 0)
的函数,编译器当然会抱怨。我将使用unsafeCoerce将前者强迫给后者。它提到了here,在newtype和它包装的类型之间使用是安全的。我想在我描述的情况下检查它是否也是安全的。
我知道这是对所有良好软件实践,类型理论,函数式编程理念,ghc策略,常识等原则的不满和反对。然而,我想知道这是否“正常”起作用。
答案 0 :(得分:6)
对于当前的GHC实施,这可能是安全的,但这不是解决您的特定问题的推荐方法。
通常使用的模式是具有这样的内部模块:
module Foo.Types (T(..)) where
newtype T = T Int
此模块在Cabal文件中声明为未导出。然后,在要使用类型的模块中,导入Types
模块,并直接使用构造函数:
module Foo.Bla where
import Foo.Types (T(..))
f :: T -> Bla
f (T int) = makeBla int
最后,您可以根据需要导出opaque类型。例如:
module Foo (T) where
import Foo.Types (T(..))
makeT :: Int -> T
makeT = T
可以使用强制,但依靠它是一个坏主意。