MK.*_*MK. 5 c haskell pointers type-safety algebraic-data-types
请考虑从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
Run Code Online (Sandbox Code Playgroud)
我不清楚函数条纹执行时在运行时会发生什么.
在编译表达式时fringe left,(1)编译器是否已经知道left树是a Branch还是a Leaf- 即它只对静态已知的树进行操作 - 或者(2)它是否发出一些if/ switch类似条件来检查left树是否为a Leaf或者一个Branch
如果它是后面的ie(2)那么,为什么这应该比等效的C函数更加类型安全,它基本上看起来就像上面那样,只是只有一种类型浮动(指向节点的指针).
Cac*_*tus 11
这个:
fringe (Leaf x) = [x]
fringe (Branch left right) = fringe left ++ fringe right
Run Code Online (Sandbox Code Playgroud)
完全等同于单个变量的函数,然后立即执行模式匹配:
fringe t = case t of
Leaf x -> [x]
Branch left right -> fringe left ++ fringe right
Run Code Online (Sandbox Code Playgroud)
所以这回答你的第一个问题为(2):"它发出一些case类似的条件来检查左边的树是a Leaf还是a Branch".
至于为什么它比你在C中做的更安全,那么,你会用C做什么?
通常你最终存储产品的一个标签,它表明,如果事情是Leaf或Branch,以及有效载荷这是不带标签的工会a和(Tree a, Tree a).然后,您编写的代码沿着以下行(这可能不是100%合法C,但应该得到重点):
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
}
Run Code Online (Sandbox Code Playgroud)
问题是没有任何东西可以静止地阻止你t.payload.Branch.left在Tree_Leaf案件中意外使用等等.此外,没有任何东西可以静静地阻止你做类似的事情
t.tag = Tree_Branch;
t.payload.Leaf.x = 42;
Run Code Online (Sandbox Code Playgroud)
这会导致"类型"的值无效Tree.