[英]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.