回答
type
声明类型同义词。类型同义词是现有类型的新名称。例如,这是多么String
定义in the standard library:
type String = [Char]
String
是为Char
的List的另一个名称。 GHC将在编译时用[Char]
替换程序中的所有用法String
。
要清楚,String
字面上是列表Char
s。这只是一个别名。您可以使用String
值的所有标准列表功能:
-- length :: [a] -> Int
ghci> length "haskell"
7
-- reverse :: [a] -> [a]
ghci> reverse "functional"
"lanoitcnuf"
data
声明一个新的数据类型,它不像一个类型的同义词,是不同于其他任何类型的不同。数据类型有多个构造函数定义您的类型的可能情况。例如,这是多么Bool
定义in the standard library:
data Bool = False | True
甲Bool
值可以是True
或False
。数据类型支持模式匹配,允许您对数据类型的值执行运行时案例分析。
yesno :: Bool -> String
yesno True = "yes"
yesno False = "no"
data
类型可以有多个构造(与Bool
),可以由其它类型的进行参数设置,可以包含在其内部其他类型,并且可以递归指自己。这里有一个例外的模型来证明这一点。一个Error a
包含类型为a
的错误消息,并可能导致错误消息。
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)
重要的是要认识到,data
声明了一个新类型,是除了系统中的任何其它类型很重要。如果String
已被声明为data
类型包含列表Char
(而不是类型同义词),您将无法使用任何列表功能。
data String = MkString [Char]
myString = MkString ['h', 'e', 'l', 'l', 'o']
myReversedString = reverse myString -- type error
还有一个更有多种类型声明:newtype
。这很像一个data
声明 - 它引入了一种独立于任何其他类型的新数据类型,并且可以进行模式匹配 - 除了您仅限于具有单个字段的单个构造函数。换句话说,newtype
是一个data
类型,它包装了一个现有的类型。
重要的区别在于成本newtype
:编译器承诺newtype
以与其包装类型相同的方式表示。打包或解包newtype
没有运行时间成本。这使得newtype
可用于制定管理(而不是结构)值之间的区别。
newtype
s与类型类很好地交互。例如,考虑Monoid
,这是一种将元素(mappend
)和特殊“空”元素(mempty
)组合在一起的类型类。 Int
可以通过多种方式制作为Monoid
,包括加0和加1.我们如何选择哪一个用于Int
的Monoid
实例?最好不要表达偏好,并使用newtype
s来启用或不使用运行时成本。复述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
随着data
创建新数据类型和声明构造它:
data NewData = NewDataConstructor
随着type
定义只是一个别名:
type MyChar = Char
在type
情况下,你可以传递的价值MyChar
类型功能期望Char
,反之亦然,但您不能这样做data MyChar = MyChar Char
。
type
作品就像let
:它允许你给一个可重复使用的名字的东西,但事情总是工作一样,如果你有内联的定义。所以
type ℝ = Double
f :: ℝ -> ℝ -> ℝ
f x y = let x2 = x^2
in x2 + y
行为完全相同的方式一样
f' :: Double -> Double -> Double
f' x y = x^2 + y
如:你可以在你的代码的任何地方与f'
,反之亦然更换f
;没有什么会改变。
OTOH,均为data
和newtype
创建不透明抽象。它们更像是一个OO中的类构造函数:即使一些值是实施仅仅根据单个数字,它不一定行为就像这样一个数字。例如,
newtype Logscaledℝ = LogScaledℝ { getLogscaled :: Double }
instance Num LogScaledℝ where
LogScaledℝ a + LogScaledℝ b = LogScaledℝ $ a*b
LogScaledℝ a - LogScaledℝ b = LogScaledℝ $ a/b
LogScaledℝ a * LogScaledℝ b = LogScaledℝ $ a**b
这里,虽然Logscaledℝ
数据是明智的仍然只是一个Double
数,它清楚地表现从Double
不同。
- 1. Rails数据类型有什么区别?
- 2. Haskell中的类型和数据类型有什么区别?
- 3. `overload`关键字有什么区别吗?
- 4. “流类型”套接字和“数据报”套接字类型有什么区别?
- 5. jquery中的数据和数据类型有什么区别?
- 6. dict.keys()中的关键字与关键字有什么区别?
- 7. 基元类和基元数据类型有什么区别?
- 8. oracle sql中的join关键字和inner join关键字有什么区别?
- 9. `pandas.read_csv`中`str`和`object`数据类型有什么区别?
- 10. MySQL中BLOB和TEXT数据类型有什么区别?
- 11. MySQL BOOL和BOOLEAN列数据类型有什么区别?
- 12. Cassandra数据类型中的INT和VARINT有什么区别?
- 13. sqlalchemy的数据类型中的Varchar和String有什么区别?
- 14. 创建结构的“数据”和“类型”有什么区别?
- 15. webassembly数据类型中的uint32和i32有什么区别?
- 16. postgresql中decimal和numeric数据类型有什么区别
- 17. 函数参数中的struct关键字有什么区别?
- 18. “throw”关键字和“Write-Error-ErrorAction Stop”之间有什么区别?
- 19. C#中的覆盖和新关键字有什么区别?
- 20. C#中的enum关键字和C有什么区别?
- 21. 关键字:is和==有什么区别python
- 22. c和C++之间关键字static有什么区别?
- 23. noexcept关键字和_NOEXCEPT宏有什么区别?
- 24. 使用box关键字和Box :: new之间有什么区别?
- 25. java和super关键字有什么区别?
- 26. 关键字'Private'和'Final'有什么区别?
- 27. 使用synchronized关键字和锁之间有什么区别
- 28. 泛型类型和泛型类型定义有什么区别?
- 29. scope“import”和“pom”类型依赖关系有什么区别?
- 30. MVC模型,数据和数据库有什么区别?