Haskell类型与数据构造函数
我正在向你学习哈斯克尔。我很难理解类型构造函数和数据构造函数。例如,我真的不明白这两者之间的区别:Haskell类型与数据构造函数,haskell,Haskell,我正在向你学习哈斯克尔。我很难理解类型构造函数和数据构造函数。例如,我真的不明白这两者之间的区别: data Car = Car { company :: String , model :: String , year :: Int } deriving (Show) 这是: data Car a b c = Car { company :: a
data Car = Car { company :: String
, model :: String
, year :: Int
} deriving (Show)
这是:
data Car a b c = Car { company :: a
, model :: b
, year :: c
} deriving (Show)
我知道第一种方法只是使用一个构造函数(
Car
)来构建Car
类型的数据。第二个我不太明白
另外,如何定义这样的数据类型:
data Color = Blue | Green | Red
data BBTree = Leaf Bool
| Branch Bool BBTree BBTree
data Config = XML_Config {...} | JSON_Config {...}
适合所有这些吗
据我所知,第三个示例(颜色
)是一种可以处于三种状态的类型:蓝色
、绿色
或红色
。但这与我对前两个示例的理解有冲突:是不是类型Car
只能处于一种状态,Car
,它可以采用各种参数来构建?如果是这样的话,第二个例子如何适用
本质上,我正在寻找一个统一上述三个代码示例/结构的解释。它是关于类型的:在第一种情况下,您设置了类型
字符串(对于公司和型号)和Int
(对于年份)。在第二种情况下,您的应用程序更通用<代码>a
、b
和c
可能与第一个示例中的类型相同,或完全不同。例如,将年份指定为字符串而不是整数可能很有用。如果你愿意,你甚至可以使用你的颜色
类型。第二种类型中有“多态性”的概念
abc
可以是任何类型。例如,a
可以是[String]
,b
可以是[Int]
而c
可以是[Char]
第一种类型是固定的:公司是字符串
,型号是字符串
,年份是Int
Car示例可能没有显示使用多态性的意义。但假设您的数据是列表类型。列表可以包含String、Char、Int…
在这些情况下,您需要第二种定义数据的方法
至于第三种方式,我认为它不需要与前一种方式相适应。这只是Haskell中定义数据的另一种方法
这是我作为初学者的拙见
顺便说一句:确保你的大脑得到良好的训练,并对此感到舒适。这是以后理解Monad的关键。从最简单的例子开始:
data Color = Blue | Green | Red
这定义了一个不带参数的“类型构造函数”Color
,它有三个“数据构造函数”Blue
、Green
和Red
。没有一个数据构造函数接受任何参数。这意味着有三种类型的颜色
:蓝色
,绿色
和红色
当需要创建某种类型的值时,使用数据构造函数。比如:
myFavoriteColor :: Color
myFavoriteColor = Green
使用Green
数据构造函数创建值myFavoriteColor
,myFavoriteColor
将为Color
类型,因为这是数据构造函数生成的值类型
当需要创建某种类型时,使用类型构造函数。在书写签名时通常会出现这种情况:
isFavoriteColor :: Color -> Bool
在本例中,您正在调用Color
类型构造函数(不带参数)
还和我在一起吗
现在,假设您不仅想要创建红/绿/蓝值,还想要指定“强度”。例如,一个介于0和256之间的值。您可以通过向每个数据构造函数添加一个参数来实现这一点,因此最终得到:
data Color = Blue Int | Green Int | Red Int
现在,三个数据构造函数中的每一个都接受类型为Int
的参数。类型构造函数(Color
)仍然不接受任何参数。所以,我最喜欢的颜色是深绿色,我可以写
myFavoriteColor :: Color
myFavoriteColor = Green 50
再次,它调用Green
数据构造函数,我得到一个Color
类型的值
想象一下,如果你不想支配人们如何表达颜色的强度。有些人可能像我们刚才那样想要一个数值。其他人可能只需要一个表示“亮”或“不太亮”的布尔值就可以了。解决方法是不要在数据构造函数中硬编码Int
,而是使用类型变量:
data Color a = Blue a | Green a | Red a
现在,我们的类型构造函数接受一个参数(另一种类型,我们称之为a
!),所有的数据构造函数将接受该类型a
的一个参数(一个值!)。所以你本来可以
myFavoriteColor :: Color Bool
myFavoriteColor = Green False
或
请注意,我们如何使用一个参数(另一种类型)调用Color
类型构造函数,以获得数据构造函数将返回的“有效”类型。这涉及到你可能想边喝一两杯咖啡边读的概念
现在我们了解了什么是数据构造函数和类型构造函数,以及数据构造函数如何将其他值作为参数,类型构造函数如何将其他类型作为参数。HTH.正如其他人指出的那样,多态性在这里并没有那么可怕的用处。让我们来看另一个您可能已经熟悉的示例:
Maybe a = Just a | Nothing
此类型有两个数据构造函数<代码>没有任何内容有点无聊,它不包含任何有用的数据。另一方面,只是
包含一个a
的值-无论a
可能有什么类型。让我们编写一个使用此类型的函数,例如获取Int
列表的头部(如果有)(我希望您同意这比抛出错误更有用):
因此在本例中,a
是一个Int
,但它也适用于任何其他类型。事实上,您可以使我们的函数适用于每种类型的列表(即使不更改实现):
另一方面,您可以编写只接受某种类型的的函数,例如
doubleMaybe :: Maybe Int -> Maybe Int
doubleMaybe Just x = Just (2*x)
doubleMaybe Nothing= Nothing
长话短说,通过多态性,您可以让您自己的类型灵活地处理其他不同类型的值
doubleMaybe :: Maybe Int -> Maybe Int
doubleMaybe Just x = Just (2*x)
doubleMaybe Nothing= Nothing
data Colour = Red | Green | Blue
data Colour = RGB Int Int Int
RGB :: Int -> Int -> Int -> Colour
Prelude> RGB 12 92 27
#0c5c1b
data SBTree = Leaf String
| Branch String SBTree SBTree
data BBTree = Leaf Bool
| Branch Bool BBTree BBTree
data BTree a = Leaf a
| Branch a (BTree a) (BTree a)
BTree :: * -> *
data Maybe a = Nothing
| Just a
Just :: a -> Maybe a
Maybe :: * -> *
[] :: [Maybe]
data Eg1 = One Int | Two String
data Eg2 = Pair Int String
data Config = XML_Config {...} | JSON_Config {...}