Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I export constructors along with a type alias?

Tags:

haskell

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
like image 275
seagreen Avatar asked Jan 06 '23 14:01

seagreen


1 Answers

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ᵢ in T(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 keyword pattern, 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 the Maybe type, without also bringing the type constructor Maybe 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 :-)

like image 89
Antal Spector-Zabusky Avatar answered Jan 15 '23 14:01

Antal Spector-Zabusky