Consider the following definition taken from a tutorial at http://www.haskell.org :
data Tree a = Leaf a | Branch (Tree a) (Tree a)
fringe :: Tree a -> [a]
fringe (Leaf x) = [x]
fringe (Branch left right) = fringe left ++ fringe right
I am unclear about what happens at runtime when the function fringe is executing.
When compiling the expression fringe left
,
(1) does the compiler somehow already know if the left
tree is a Branch
or
a Leaf
- i.e. it only operates on statically known trees - or (2) does it emit some if
/switch
like conditions to check if the left
tree is a Leaf
or a Branch
If it is the later i.e. (2), then, why is this supposed to be more typesafe than the equivalent C function which basically would look just like above except that there is only one type floating around (pointer to a node).
答案 0 :(得分:11)
此:
fringe (Leaf x) = [x]
fringe (Branch left right) = fringe left ++ fringe right
完全等同于单个变量的函数,然后立即进行模式匹配:
fringe t = case t of
Leaf x -> [x]
Branch left right -> fringe left ++ fringe right
所以这回答你的第一个问题为(2):"它发出[s]一些case
- 类似的条件来检查左边的树是Leaf
还是{{1 }}"
至于为什么它比你在C中所做的更安全,那么,你会用C做什么?
通常,您最终会存储标记的产品,以显示某些内容是Branch
还是Leaf
,以及有效内容是{{1}的无标记联合}和Branch
。然后,你编写的代码是沿着下面的代码(这可能不是100%合法的C,但应该得到重点):
a
问题在于,在(Tree a, Tree a)
案例等情况下,您无意中无意中使用enum TreeTag { Tree_Leaf; Tree_Branch; };
struct Tree {
TreeTag tag;
union payload {
struct {
int x; // yeah let's not touch on parametric polymorphism here...
} Leaf;
struct {
Tree l;
Tree r;
} Branch;
};
};
switch (t.tag) {
case Tree_Leaf: ... use t.payload.Leaf.x here
case Tree_Branch: ... use t.payload.Branch.left and t.payload.Branch.right here
}
。此外,没有任何东西可以阻止你做像
t.payload.Branch.left
会导致"类型"的无效值Tree_Leaf
。