“数据”与“数据”之间有什么区别?和“类型”关键字? [英] What's the difference between "data" and "type" keywords?
问题描述
数据
和类型
关键字总是让我困惑。 我想知道 data
和 type $ c之间的区别$ c>以及如何使用它们。
String
是如何定义的在标准库中: type String = [Char]
字符串
是一个 Char
s的列表。 GHC将在编译时用 [Char]
替换程序中 String
的所有用法。
明确地说,字符串 字面上是
Char
code>秒。这只是一个别名。您可以使用字符串
值中的所有标准列表函数:
- - 长度:: [a] - > Int
ghci>长度haskell
7
- 反向:: [a] - > [a]
ghci>反向功能性
lanoitcnuf
data
声明一个新数据类型,与类型同义词不同,它与其他类型不同。数据类型有许多构造函数定义您的类型的可能情况。例如,这是如何定义 Bool
标准库:
data Bool = False | True
Bool
值可以是 True
或 False
。数据类型支持模式匹配,允许您对数据类型的值执行运行时案例分析。
yesno :: Bool - >字符串
yesno True =是
yesno False =no
data
类型可以有多个构造函数(如 Bool
),可以由其他类型参数化,可以包含其他类型他们,并可以递归引用自己。这里有一个例外的模型来证明这一点。 错误包含
a
类型的错误消息,并且可能是导致它的错误。
数据错误a =错误{值:: a,原因::可能错误}
类型ErrorWithMessage =错误字符串
myError1,myError2 :: ErrorWithMessage
myError1 =错误woops没有
myError2 =错误myError1被抛出(只是myError1)
认识到 data
声明了一个与系统中任何其他类型不同的新类型是很重要的。如果 String
已被声明为 data
type 包含<$ c $的列表c> Char s(而不是类型同义词),您将无法使用任何列表函数。
data String = MkString [Char]
myString = MkString ['h','e','l','l','o']
myReversedString = reverse myString - 类型错误
还有一种类型声明: newtype
。这很像 data
声明 - 它引入了一种独立于任何其他类型的新数据类型,并且可以进行模式匹配 - 除了仅限于一个构造函数领域。换句话说, newtype
是包装现有类型的 data
类型。
重要的区别是 newtype
的成本:编译器承诺 newtype
的表现方式与其包装的类型相同。打包或解包 newtype
不需要运行时间成本。这使得 newtype
对于使管理(而不是结构)区分值有用。
newtype
s与类型类很好地交互。例如,考虑 Monoid
,这是一种类型的类,它可以将元素( mappend
)和一个特殊的'empty '元素( mempty
)。 Int
可以通过很多方式变成 Monoid
,包括加0和乘1.我们如何选择哪一个可用于 Monoid
Int实例
的实例?最好不要表达首选项,并使用 newtype
s来启用没有运行时成本的使用。解释标准库 :
- 引入一个带有构造函数Sum的Sum类,它包装一个Int和一个提取器getSum,
newtype Sum = Sum {getSum :: Int}
实例Monoid Sum其中
(Sum x)`mappend`(Sum y)= Sum(x + y)
mempty =总和0
newtype Product = Product {getProduct :: Int}
实例Monoid Product其中
(Product x)`mappend`(Product y)= Product(x * y)
mempty =产品1
The data
and type
keywords always confuse me.
I want to know what is the difference between data
and type
and how to use them.
type
declares a type synonym. A type synonym is a new name for an existing type. For example, this is how String
is defined in the standard library:
type String = [Char]
String
is another name for a list of Char
s. GHC will replace all usages of String
in your program with [Char]
at compile-time.
To be clear, a String
literally is a list of Char
s. It's just an alias. You can use all the standard list functions on String
values:
-- length :: [a] -> Int
ghci> length "haskell"
7
-- reverse :: [a] -> [a]
ghci> reverse "functional"
"lanoitcnuf"
data
declares a new data type, which, unlike a type synonym, is different from any other type. Data types have a number of constructors defining the possible cases of your type. For example, this is how Bool
is defined in the standard library:
data Bool = False | True
A Bool
value can be either True
or False
. Data types support pattern matching, allowing you to perform a runtime case-analysis on a value of a data type.
yesno :: Bool -> String
yesno True = "yes"
yesno False = "no"
data
types can have multiple constructors (as with Bool
), can be parameterised by other types, can contain other types inside them, and can recursively refer to themselves. Here's a model of exceptions which demonstrates this; an Error a
contains an error message of type a
, and possibly the error which caused it.
data Error a = Error { value :: a, cause :: Maybe Error }
type ErrorWithMessage = Error String
myError1, myError2 :: ErrorWithMessage
myError1 = Error "woops" Nothing
myError2 = Error "myError1 was thrown" (Just myError1)
It's important to realise that data
declares a new type which is apart from any other type in the system. If String
had been declared as a data
type containing a list of Char
s (rather than a type synonym), you wouldn't be able to use any list functions on it.
data String = MkString [Char]
myString = MkString ['h', 'e', 'l', 'l', 'o']
myReversedString = reverse myString -- type error
There's one more variety of type declaration: newtype
. This works rather like a data
declaration - it introduces a new data type separate from any other type, and can be pattern matched - except you are restricted to a single constructor with a single field. In other words, a newtype
is a data
type which wraps up an existing type.
The important difference is the cost of a newtype
: the compiler promises that a newtype
is represented in the same way as the type it wraps. There's no runtime cost to packing or unpacking a newtype
. This makes newtype
s useful for making administrative (rather than structural) distinctions between values.
newtype
s interact well with type classes. For example, consider Monoid
, the class of types with a way to combine elements (mappend
) and a special 'empty' element (mempty
). Int
can be made into a Monoid
in many ways, including addition with 0 and multiplication with 1. How can we choose which one to use for a possible Monoid
instance of Int
? It's better not to express a preference, and use newtype
s to enable either usage with no runtime cost. Paraphrasing the standard library:
-- introduce a type Sum with a constructor Sum which wraps an Int, and an extractor getSum which gives you back the Int
newtype Sum = Sum { getSum :: Int }
instance Monoid Sum where
(Sum x) `mappend` (Sum y) = Sum (x + y)
mempty = Sum 0
newtype Product = Product { getProduct :: Int }
instance Monoid Product where
(Product x) `mappend` (Product y) = Product (x * y)
mempty = Product 1
这篇关于“数据”与“数据”之间有什么区别?和“类型”关键字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!