[英]Haskell usage of data type
我正在阅读制作我们自己的类型和类型类来学习你的哈克尔。
在代数数据类型介绍中我注意到:
data Point = Point Float Float deriving (Show)
data Shape = Circle Point Float | Rectangle Point Point deriving (Show)
surface :: Shape -> Float
surface (Rectangle (Point x1 y1) (Point x2 y2)) = abs (x2 - x1) * abs (y2 - y1)
在surface (Rectangle (Point x1 y1) (Point x2 y2))
,我们指出Rectangle的参数是Point类型。
但是,在递归数据结构部分中:
data Tree a = EmptyTree | Node a (Tree a) (Tree a) deriving (Show, Read, Eq)
singleton :: a -> Tree a
singleton x = Node x EmptyTree EmptyTree
treeInsert :: (Ord a) => a -> Tree a -> Tree a
treeInsert x EmptyTree = singleton x
treeInsert x (Node a left right)
| x == a = Node x left right
| x < a = Node a (treeInsert x left) right
| x > a = Node a left (treeInsert x right)
我们没有指出left
和right
的数据类型是treeInsert x (Node a left right)
中的Tree a
treeInsert x (Node a left right)
。 编译器如何知道它们的类型?
我觉得你有一个误解:
在
surface (Rectangle (Point x1 y1) (Point x2 y2))
,我们指出Rectangle的参数是Point
类型。
这确实表明参数属于point类型,但可能与您的想法不同。 Point x1 y1
的“ Point
”不是一个类型 - 它是一个构造函数,其命名方式与它构造的类型相同。 如果我们宣布Point
为
data Point = MakePoint Float Float
然后你会说
surface (Rectangle (MakePoint x1 y1) (MakePoint x2 y2))
为清楚起见,我将继续使用MakePoint
作为构造函数,使用Point
作为类型。 合法的Haskell将其命名为相同,因为编译器总是可以从上下文中判断,但人类有时会遇到更多麻烦。
在上下文中
surface (Rectangle (MakePoint x1 y1) (MakePoint x2 y2)) = ...
我们知道子表达式MakePoint x1 y1
具有来自两个不同位置的Point
类型。 一个是构造函数Rectangle
具有类型
Rectangle :: Point -> Point -> Shape
所以我们知道,无论它的参数必须是点(这是由外向内的类型推断,我们得到的来自其中它的使用范围内的事情型); 另一个是构造函数MakePoint
有类型
MakePoint :: Float -> Float -> Point
所以我们知道MakePoint x1 y1
表示Point
类型的值(这是由里而外的类型推断,我们从其组件中获取表达式的类型)。 在某种程度上,编译器使用这两种方法并确保它们匹配。
但是,有时缺少这些信息中的一种或另一种,例如我们的例子中的x1
。 我们没有关于x1
内部信息(好吧,如果我们查看方程式的右侧,编译器也MakePoint
,但我们现在忽略它),我们所拥有的只是MakePoint
的参数构造函数必须是Float
,所以我们知道x1
必须是Float
。 这是编译器有效和推断的; 没有必要明确说明。
在Tree
例子中,更令人困惑的命名正在进行(一旦你得到它,不再混淆并开始有用,但最好在开始时画出明显的区别),所以我要重命名第一个Node
从a
到v
:
treeInsert :: (Ord a) => a -> Tree a -> Tree a
treeInsert x EmptyTree = singleton x
treeInsert x (Node v left right)
| x == v = Node x left right
| x < v = Node v (treeInsert x left) right
| x > v = Node v left (treeInsert x right)
同样的事情与发生left
和right
这一点与x1
上面:没有由内而外的结构使用,但我们知道, Node
构造函数采用a
和两个Tree a
S,所以v
的类型必须是a
,和left
和right
必须是Tree a
类型。 编译器从上下文中推断出这一点。
在surface
(Rectangle (Point x1 y1) (Point x2 y2))
,我们指出Rectangle的参数是Point类型。
不,这是你的错误观念。 由于数据声明,编译器知道Rectangle
参数的类型:
data ... | Rectangle Point Point
在您引用的代码中:
surface (Rectangle (Point x1 y1) (Point x2 y2))
这称为模式匹配。 Surface采用矩形,我们将模式匹配,以便将变量名称绑定到参数。 我们还对每个参数进行模式匹配以获得对子参数的访问并绑定变量名称x1
, y1
, x2
和y2
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.