我正在努力学习Haskell。
我正在阅读这里的代码[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
答案 0 :(得分:5)
这意味着"导出此数据类型的所有构造函数和记录字段"。
编写模块导出列表时,可以使用三种 4 方式导出数据类型:
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 }
答案 1 :(得分:5)
导入/导出列表的语法与Haskell本身的语法没有多大关系。它只是一个以逗号分隔的列表,列出了您要从模块中导出的所有内容。现在,那里存在一个问题,因为Haskell确实有两种语言,其符号可能具有相同的名称。这在newtype
中特别常见,例如您的示例:您有类型级别名称 SharedSeed :: *
,还有值级名称(数据构造函数){ {1}}。
这只发生在大写名称中,因为类型级别的小写始终是本地类型变量。因此,导出列表中的约定大写名称引用类型。
但只是导出该类型不允许用户实际构造该类型的值。这通常是谨慎的:并非所有内部代表值都可能构成新类型的合法值(请参阅Bartek's example),因此最好只导出一个安全的智能构造函数而不是不安全的数据构造函数。
但有时候,你确实希望使数据构造函数可用,当然对于像SharedSeed :: ByteString -> SharedSeed
这样的多构造函数类型。为此,导出列表有三种语法可供您使用:
Maybe
module Pos.Core.Types(
将导出构造函数SharedSeed (SharedSeed)
。在这种情况下,这当然是唯一的构造函数,但是如果有其他构造函数,他们将 以这种语法导出。
SharedSeed
将导出所有构造函数。同样,在这种情况下,只有SharedSeed (..)
,但对于例如SharedSeed
它会导出Maybe
和Nothing
。
Just
会将pattern SharedSeed
导出为独立模式(独立于ShareSeed
类型的导出)。这需要-XPatternSynonyms
extension。
ShareSeed