Haskell 类型与数据构造函数 [英] Haskell Type vs Data Constructor

查看:38
本文介绍了Haskell 类型与数据构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从 learnyouahaskell.com 学习 Haskell.我无法理解类型构造函数和数据构造函数.例如,我不太明白这之间的区别:

I am learning Haskell from learnyouahaskell.com. I am having trouble understanding type constructors and data constructors. For example, I don't really understand the difference between this:

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 类型的数据.我真的不明白第二个.

I understand that the first is simply using one constructor (Car) to built data of type Car. I don't really understand the second one.

另外,数据类型是如何定义的:

Also, how do data types defined like this:

data Color = Blue | Green | Red

适合所有这些吗?

据我所知,第三个示例(Color)是一种可以处于三种状态的类型:BlueGreen 或 <代码>红色.但这与我对前两个示例的理解相冲突:是不是 Car 类型只能处于一种状态,Car,它可以使用各种参数来构建?如果是这样,第二个例子如何适合?

From what I understand, the third example (Color) is a type which can be in three states: Blue, Green or Red. But that conflicts with how I understand the first two examples: is it that the type Car can only be in one state, Car, which can take various parameters to build? If so, how does the second example fit in?

本质上,我正在寻找统一上述三个代码示例/结构的解释.

Essentially, I am looking for an explanation that unifies the above three code examples/constructs.

推荐答案

data 声明中,类型构造函数是位于等号左侧的东西符号.数据构造器是等号右侧的东西.在需要类型的地方使用类型构造函数,在需要值的地方使用数据构造函数.

In a data declaration, a type constructor is the thing on the left hand side of the equals sign. The data constructor(s) are the things on the right hand side of the equals sign. You use type constructors where a type is expected, and you use data constructors where a value is expected.

为了简单起见,我们可以从代表颜色的类型的示例开始.

To make things simple, we can start with an example of a type that represents a colour.

data Colour = Red | Green | Blue

这里,我们有三个数据构造函数.Colour 是一个类型,Green 是一个构造函数,它包含一个 Colour 类型的值.类似地,RedBlue 都是构造 Colour 类型值的构造函数.不过,我们可以想象给它加点料!

Here, we have three data constructors. Colour is a type, and Green is a constructor that contains a value of type Colour. Similarly, Red and Blue are both constructors that construct values of type Colour. We could imagine spicing it up though!

data Colour = RGB Int Int Int

我们仍然只有 Colour 类型,但是 RGB 不是一个值——它是一个函数,它接受三个 Ints 并返回一个值!RGB 有类型

We still have just the type Colour, but RGB is not a value – it's a function taking three Ints and returning a value! RGB has the type

RGB :: Int -> Int -> Int -> Colour

RGB 是一个数据构造函数,它是一个函数,它以一些作为参数,然后使用这些值来构造一个新值.如果你做过任何面向对象的编程,你应该认识到这一点.在 OOP 中,构造函数也将一些值作为参数并返回一个新值!

RGB is a data constructor that is a function taking some values as its arguments, and then uses those to construct a new value. If you have done any object-oriented programming, you should recognise this. In OOP, constructors also take some values as arguments and return a new value!

在这种情况下,如果我们将 RGB 应用于三个值,我们将得到一个颜色值!

In this case, if we apply RGB to three values, we get a colour value!

Prelude> RGB 12 92 27
#0c5c1b

我们通过应用数据构造函数构造了一个 Colour 类型的值.数据构造函数要么像变量一样包含一个值,要么将其他值作为其参数并创建一个新的.如果你之前做过编程,这个概念你应该不会很陌生.

We have constructed a value of type Colour by applying the data constructor. A data constructor either contains a value like a variable would, or takes other values as its argument and creates a new value. If you have done previous programming, this concept shouldn't be very strange to you.

如果你想构造一个二叉树来存储String,你可以想象做类似

If you'd want to construct a binary tree to store Strings, you could imagine doing something like

data SBTree = Leaf String
            | Branch String SBTree SBTree

我们在这里看到的是一个类型SBTree,它包含两个数据构造函数.换句话说,有两个函数(即LeafBranch)将构造SBTree 类型的值.如果您不熟悉二叉树的工作原理,请坚持下去.你实际上并不需要知道二叉树是如何工作的,只需要知道这个二叉树以某种方式存储 String .

What we see here is a type SBTree that contains two data constructors. In other words, there are two functions (namely Leaf and Branch) that will construct values of the SBTree type. If you're not familiar with how binary trees work, just hang in there. You don't actually need to know how binary trees work, only that this one stores Strings in some way.

我们还看到两个数据构造函数都接受一个 String 参数——这是它们要存储在树中的字符串.

We also see that both data constructors take a String argument – this is the String they are going to store in the tree.

但是!如果我们还希望能够存储 Bool,我们必须创建一个新的二叉树.它可能看起来像这样:

But! What if we also wanted to be able to store Bool, we'd have to create a new binary tree. It could look something like this:

data BBTree = Leaf Bool
            | Branch Bool BBTree BBTree

类型构造函数

SBTreeBBTree 都是类型构造函数.但是有一个明显的问题.你看到它们有多相似了吗?这表明您确实需要某个参数.

Type constructors

Both SBTree and BBTree are type constructors. But there's a glaring problem. Do you see how similar they are? That's a sign that you really want a parameter somewhere.

所以我们可以这样做:

data BTree a = Leaf a
             | Branch a (BTree a) (BTree a)

现在我们引入一个类型变量 a 作为类型构造函数的参数.在这个声明中,BTree 变成了一个函数.它接受一个 type 作为它的参数,并返回一个新的 type.

Now we introduce a type variable a as a parameter to the type constructor. In this declaration, BTree has become a function. It takes a type as its argument and it returns a new type.

在这里考虑具体类型之间的区别很重要(示例包括Int[Char]Maybe Bool) 是一种可以分配给程序中的值的类型,以及一个类型构造函数,您需要提供一个类型才能分配给一个值.值永远不能是list"类型,因为它必须是list of something".本着同样的精神,值永远不能是二叉树"类型,因为它必须是存储东西"的二叉树.

It is important here to consider the difference between a concrete type (examples include Int, [Char] and Maybe Bool) which is a type that can be assigned to a value in your program, and a type constructor function which you need to feed a type to be able to be assigned to a value. A value can never be of type "list", because it needs to be a "list of something". In the same spirit, a value can never be of type "binary tree", because it needs to be a "binary tree storing something".

如果我们将 Bool 作为参数传入 BTree,它会返回类型 BTree Bool,这是一个二叉树存储 Bool s.将每次出现的类型变量 a 替换为类型 Bool,您就可以亲眼看到它是如何正确的.

If we pass in, say, Bool as an argument to BTree, it returns the type BTree Bool, which is a binary tree that stores Bools. Replace every occurrence of the type variable a with the type Bool, and you can see for yourself how it's true.

如果您愿意,可以将 BTree 视为具有 kind

If you want to, you can view BTree as a function with the kind

BTree :: * -> *

Kinds 有点像类型——* 表示具体类型,所以我们说BTree 是从具体类型到具体类型.

Kinds are somewhat like types – the * indicates a concrete type, so we say BTree is from a concrete type to a concrete type.

退后一步,注意相似之处.

Step back here a moment and take note of the similarities.

  • 数据构造函数是一个函数",它接受0个或多个并返回一个新值.

  • A data constructor is a "function" that takes 0 or more values and gives you back a new value.

类型构造函数是一个函数",它接受0个或多个类型并返回一个新类型.

A type constructor is a "function" that takes 0 or more types and gives you back a new type.

如果我们希望我们的值有细微的变化,带参数的数据构造函数很酷——我们把这些变化放在参数中,让创建值的人决定他们要放入什么参数.同样的,类型构造函数如果我们希望我们的类型稍有变化,参数是很酷的!我们将这些变体作为参数,让创建类型的人决定他们要放入哪些参数.

Data constructors with parameters are cool if we want slight variations in our values – we put those variations in parameters and let the guy who creates the value decide what arguments they are going to put in. In the same sense, type constructors with parameters are cool if we want slight variations in our types! We put those variations as parameters and let the guy who creates the type decide what arguments they are going to put in.

作为这里的主线,我们可以考虑 Maybe a 类型.它的定义是

As the home stretch here, we can consider the Maybe a type. Its definition is

data Maybe a = Nothing
             | Just a

这里,Maybe 是一个返回具体类型的类型构造函数.Just 是一个返回值的数据构造函数.Nothing 是一个包含值的数据构造函数.如果我们查看 Just 的类型,我们会看到

Here, Maybe is a type constructor that returns a concrete type. Just is a data constructor that returns a value. Nothing is a data constructor that contains a value. If we look at the type of Just, we see that

Just :: a -> Maybe a

换句话说,Just 接受一个 a 类型的值并返回一个 Maybe a 类型的值.如果我们看一下 Maybe 的类型,我们会看到

In other words, Just takes a value of type a and returns a value of type Maybe a. If we look at the kind of Maybe, we see that

Maybe :: * -> *

换句话说,Maybe 接受一个具体类型并返回一个具体类型.

In other words, Maybe takes a concrete type and returns a concrete type.

再来一次!具体类型和类型构造函数之间的区别.您无法创建 Maybe 的列表 - 如果您尝试执行

Once again! The difference between a concrete type and a type constructor function. You cannot create a list of Maybes - if you try to execute

[] :: [Maybe]

你会得到一个错误.但是,您可以创建 Maybe IntMaybe a 的列表.那是因为 Maybe 是一个类型构造函数,但是一个列表需要包含一个具体类型的值.Maybe IntMaybe a 是具体类型(或者,如果需要,可以调用返回具体类型的类型构造函数.)

you'll get an error. You can however create a list of Maybe Int, or Maybe a. That's because Maybe is a type constructor function, but a list needs to contain values of a concrete type. Maybe Int and Maybe a are concrete types (or if you want, calls to type constructor functions that return concrete types.)

这篇关于Haskell 类型与数据构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆