我可以将构造函数与类型别名一起导出吗?

时间:2016-02-25 00:34:53

标签: haskell

我有一个数据类型data Foo a b = Bar a b,我在库中内部使用。

我还有一个更常见的具体形式的别名:type Bar = Foo Int Int

有没有办法从我的库中导出Bar类型而不是Foo类型?

我想做:

module Quux (
    Bar(Bar)
  ) where

但是当我尝试这个时,我得到错误:

The export item ‘Bar(Bar)’
attempts to export constructors or class methods that are not visible here

以下内容可行,但我不想导出Foo类型:

module Quux (
    Bar
  , Foo(..)
  ) where

3 个答案:

答案 0 :(得分:4)

这个在Haskell 2010中不可能,但在GHC中

在Haskell 2010 中,您只能将构造函数导出为数据类型的一部分:

  

除了作为下级名称[{1}}]中的Cᵢ之外,不能在导出列表中命名数据构造函数,因为它们无法与类型构造函数区分开来。 [Haskell 2010 Report, §5.2 "Export Lists", #2]

在GHC version 7.8 or later)中,您可以使用T(C₁,C₂)语言扩展来完成此操作:启用该功能后,您可以在导出列表中限定构造函数PatternSynonyms。因此,例如,您想要的例子是

pattern

导出列表中的{-# LANGUAGE PatternSynonyms #-} module Quux (Bar, pattern Bar) where data Foo a b = Bar a b type Bar = Foo Int Int 指定构造函数,而未校对的pattern Bar指定类型同义词。

此外,如果您认为未经修饰的Bar令人困惑/不明确,您可以使用Bar扩展名(在7.6或更高版本中)启用带ExplicitNamespaces的前缀类型构造函数,类似地:

type

从文档中,关于使用{-# LANGUAGE ExplicitNamespaces, PatternSynonyms #-} module Quux (type Bar, pattern Bar) where data Foo a b = Bar a b type Bar = Foo Int Int 导出构造函数:

  

[W] ith pattern您可以在导入或导出列表中使用关键字-XPatternSynonyms作为数据构造函数名称的前缀,以允许导入或导出不带父类型的数据构造函数构造函数[GHC 7.10 Users Manual, §7.3.26.4 "Explicit namespaces in import/export"]

  

您还可以在导入/导出规范中使用pattern关键字来导入或导出普通数据构造函数。例如:

pattern
     

会将import Data.Maybe( pattern Just ) 类型的数据构造函数Just纳入范围,而不会将类型构造函数Maybe纳入范围。 [GHC 7.10 Users Manual, §7.3.9.2 "Import and export of pattern synonyms"]

另外,对于导出Maybe的类型:

  

type扩展名允许您在导入或导出列表中使用" -XExplicitNamespaces"作为类型构造函数的名称的前缀。消除歧义... [GHC 7.10 Users Manual, §7.3.26.4 "Explicit namespaces in import/export"]

那就是说,我倾向于同意这里的dfeuer - 这是报告不允许这样做的原因。键入无法记下的签名 - 例如type - 有点令人抓狂。但类型同义词对此有帮助;只需确保您的文档彻底: - )

答案 1 :(得分:2)

你为什么要这样做?不,不要打扰回答。 不要这样做。无论你认为它会完成什么,它都不会。然而, 可以做的是使用newtype(注意我稍微更改了名称):

newtype Bar = _Bar (Foo Int Int)
data Foo a b = Foo a b

现在您可以使用模式同义词使Bar用户友好:

{-# LANGUAGE PatternSynonyms #-}

module Whatever (Bar, pattern Bar)
pattern Bar a b = _Bar (Foo a b)

有一点奇怪的是必须使用pattern关键字来导入同义词,但是哦。与您的方法不同,最终用户可以访问适当的头等类型,而不仅仅是同义词。他们无法看到Foo的任何内容。

答案 2 :(得分:1)

您可以只使用Bar导出module Quux (Bar) where ...类型,但您无法构建任何Bar

如果你还需要构造函数,你可以使用类似的技术smart constructors,即创建一个帮助函数,创建Bar并导出那个:

module Quux (Bar, bar) where

data Foo a b = Foo a b
type Bar = Foo Int Int

bar :: Int -> Int -> Bar
bar = Foo

然后

\> let b = bar 1 2
\> :type b
b :: Bar
\> let f = Foo 1 2

<interactive>:9:9: Not in scope: data constructor ‘Foo’