Скрыть конструктор, но не тип при импорте



У меня есть внутренний модуль, для которого я хотел бы предоставить внешний API



module Positive.Internal where

newtype Positive a = Positive { getPositive :: a }
deriving (Eq, Ord)

-- smart constructor
toPositive :: (Num a, Ord a) => a -> Maybe (Positive a)
toPositive a | a <= 0 = Nothing
| otherwise = Just $ Positive a
-- ...


Я хочу скрыть тупой конструктор и заменить его однонаправленным
чтобы пользователи все еще могли сопоставлять значения шаблону, им просто нужно использовать интеллектуальный конструктор для использования новых значений.



Поскольку я хочу, чтобы шаблон и тупой конструктор использовали одно и то же имя, мне нужно скрыть тупой конструктор, чтобы предотвратить столкновения пространств имен.



Однако, поскольку тупой конструктор и тип совместно используются имена, это немного сложно импортировать все, кроме тупого конструктора.



В настоящее время я делаю это, что работает нормально:



{-# LANGUAGE PatternSynonyms #-}
module Positive
( module Positive.Internal, pattern Positive
) where

import Positive.Internal (Positive())
import Positive.Internal hiding (Positive)
import qualified Positive.Internal as Internal

pattern Positive :: a -> Positive a
pattern Positive a <- Internal.Positive a


Я мог бы упростить свой импорт, просто используя квалифицированный импорт, но мне любопытно.

Есть ли способ в одном операторе импорта импортировать все Positive.Internal, кроме немого конструктора?



Я пробовал hiding (Positive(Positive)), но это скрывало и тип, и тупой конструктор. Я покопался в Вики , но я не заметил никакого способа различайте конструкторы и типы в списках hiding.

495   1  

1 ответ:

Поправьте меня, если я ошибаюсь, но я почти уверен, что это то, что вы ищете:

{-# LANGUAGE PatternSynonyms #-}
module Positive
  ( module Positive.Internal, pattern Positive, foo
  ) where

import Positive.Internal hiding (pattern Positive)
import qualified Positive.Internal as Internal (pattern Positive)

pattern Positive :: a -> Positive a
pattern Positive a <- Internal.Positive a

foo :: Positive Int
foo = Internal.Positive 5

Internal модуль остается таким же, как он определен до сих пор. И ради примера:

module Negative where

import Positive

bar :: Maybe Int
bar = getPositive <$> toPositive 6

Давайте перепроверим GHCi:

Prelude> :load Negative
[1 of 3] Compiling Positive.Internal ( Positive/Internal.hs, interpreted )
[2 of 3] Compiling Positive         ( Positive.hs, interpreted )
[3 of 3] Compiling Negative         ( Negative.hs, interpreted )
Ok, modules loaded: Negative, Positive, Positive.Internal.
*Negative> bar
Just 6
*Negative> getPositive foo
5
*Negative> :i Positive
newtype Positive a = Positive.Internal.Positive {getPositive :: a}
    -- Defined at Positive/Internal.hs:3:1
instance [safe] Ord a => Ord (Positive a)
  -- Defined at Positive/Internal.hs:4:17
instance [safe] Eq a => Eq (Positive a)
  -- Defined at Positive/Internal.hs:4:13
*Negative> :t Positive

<interactive>:1:1: error:
    • non-bidirectional pattern synonym ‘Positive’ used in an expression
    • In the expression: Positive

Comments

    Ничего не найдено.