Что означает?
Я пытаюсь выучить Хаскель.
Я читаю код здесь [1]. Я просто копирую и вставляю часть кода из строк:46 и 298-300.
Вопрос: Что означает (..)?
Я толкнул это, но у меня не было результата.
module Pos.Core.Types(
-- something here
SharedSeed (..) -- what does this mean?
) where
newtype SharedSeed = SharedSeed
{ getSharedSeed :: ByteString
} deriving (Show, Eq, Ord, Generic, NFData, Typeable)
[1] https://github.com/input-output-hk/cardano-sl/blob/master/core/Pos/Core/Types.hs
2 ответа
Это означает "экспортировать все конструкторы и записи полей для этого типа данных".
При написании списка экспорта модулей есть три способа экспорта данных:
module ModuleD(
D, -- just the type, no constructors
D(..), -- the type and all its constructors
D(DA) -- the type and the specific constructor
) where
data D = DA A | DB B
Если вы не экспортируете никаких конструкторов, тип, ну, не может быть создан, по крайней мере, напрямую. Это полезно, например, если вы хотите применить некоторые инварианты времени выполнения для типа данных:
module Even (evenInt, toInt) where
newtype EvenInt = EvenInt Int deriving (Show, Eq)
evenInt :: Int -> Maybe EvenInt
evenInt x = if x `mod` 2 == 0 then Just x else Nothing
toInt :: EvenInt -> Int
toInt (EvenInt x) = x
Код вызывающей стороны теперь может использовать этот тип, но только разрешенным способом:
x = evenInt 2
putStrLn $ if isJust x then show . toInt . fromJust $ x else "Not even!"
Как примечание стороны, toInt
для удобства обычно реализуется косвенно через синтаксис записи:
data EvenInt = EvenInt { toInt :: Int }
4 См. Ответ @leftaroundabout
Синтаксис списков импорта / экспорта не имеет ничего общего с синтаксисом самого Haskell. Это просто разделенный запятыми список всего, что вы хотите экспортировать из вашего модуля. Теперь есть проблема, потому что на Хаскеле действительно есть два языка с символами, которые могут иметь одинаковое имя. Это особенно характерно для newtype
как в вашем примере: у вас есть имя уровня типа SharedSeed :: *
, а также имя уровня значения (конструктор данных) SharedSeed :: ByteString -> SharedSeed
,
Это происходит только с заглавными именами, потому что строчные буквы на уровне типа всегда являются локальными переменными типа. Таким образом, соглашение в списках экспорта, что имена в верхнем регистре относятся к типам.
Но простой экспорт типа не позволяет пользователям фактически создавать значения этого типа. Это часто разумно: не все значения внутреннего представления могут принимать допустимые значения для нового типа (см . Пример Бартека), поэтому лучше экспортировать только безопасный умный конструктор вместо небезопасного конструктора данных.
Но в других случаях вы хотите сделать конструктор данных доступным, конечно, для мультиконструктивных типов, таких как Maybe
, Для этого списки экспорта имеют три синтаксиса, которые вы можете использовать:
module Pos.Core.Types(
SharedSeed (SharedSeed)
будет экспортировать конструкторSharedSeed
, В этом случае это, конечно, единственный конструктор в любом случае, но если бы были другие конструкторы, они не экспортировались бы с этим синтаксисом.SharedSeed (..)
будет экспортировать все конструкторы. Опять же, в этом случае это толькоSharedSeed
но, например,Maybe
это будет экспортировать обаNothing
а такжеJust
,pattern SharedSeed
будет экспортироватьShareSeed
в качестве отдельного шаблона (независимо от экспортаShareSeed
тип). Это требует-XPatternSynonyms
расширение.)