我有一个数据类型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
答案 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’