I have a data type data Foo a b = Bar a b
that I use internally in a library.
I also have an alias for one of its more common concrete forms: type Bar = Foo Int Int
.
Is there a way to export the Bar
type, but not the Foo
type from my library?
I'd like to do:
module Quux (
Bar(Bar)
) where
But when I attempt this I get the error:
The export item ‘Bar(Bar)’
attempts to export constructors or class methods that are not visible here
The below would work, except I'd rather not export the Foo
type at all:
module Quux (
Bar
, Foo(..)
) where
This isn't possible in Haskell 2010, but is possible in GHC.
In Haskell 2010, you can only export constructors as part of a data type:
Data constructors cannot be named in export lists except as subordinate names [the
Cᵢ
inT(C₁,C₂)
], because they cannot otherwise be distinguished from type constructors. [Haskell 2010 Report, §5.2 "Export Lists", #2]
In GHC (version 7.8 or later), however, you can use the PatternSynonyms
language extension to accomplish this: with that turned on, you can qualify constructors in export lists with pattern
. So, for instance, your desired example would be
{-# LANGUAGE PatternSynonyms #-}
module Quux (Bar, pattern Bar) where
data Foo a b = Bar a b
type Bar = Foo Int Int
The pattern Bar
in the export list specifies the constructor, and the unadorned Bar
specifies the type synonym.
In addition, if you think the unadorned Bar
is confusing/ambiguous, you can use the ExplicitNamespaces
extension (in version 7.6 or later) to enable prefixing type constructors with type
, similarly:
{-# LANGUAGE ExplicitNamespaces, PatternSynonyms #-}
module Quux (type Bar, pattern Bar) where
data Foo a b = Bar a b
type Bar = Foo Int Int
From the documentation, about exporting constructors with pattern
:
[W]ith
-XPatternSynonyms
you can prefix the name of a data constructor in an import or export list with the keywordpattern
, to allow the import or export of a data constructor without its parent type constructor [GHC 7.10 Users Manual, §7.3.26.4 "Explicit namespaces in import/export"]
and
You may also use the
pattern
keyword in an import/export specification to import or export an ordinary data constructor. For example:import Data.Maybe( pattern Just )
would bring into scope the data constructor
Just
from theMaybe
type, without also bringing the type constructorMaybe
into scope. [GHC 7.10 Users Manual, §7.3.9.2 "Import and export of pattern synonyms"]
Plus, for exporting types with type
:
The
-XExplicitNamespaces
extension allows you to prefix the name of a type constructor in an import or export list with "type
" to disambiguate… [GHC 7.10 Users Manual, §7.3.26.4 "Explicit namespaces in import/export"]
That said, I am inclined to agree with dfeuer here – there's a reason the report disallows this. Type signatures that are impossible to write down – e.g., Bar :: a -> b -> Quux.Foo a b
– are a bit maddening. But the type synonym does help with that; just make sure your documentation is thorough :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With