繁体   English   中英

haskell中的递归数据类型

[英]recursive datatypes in haskell

请考虑从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

我不清楚函数条纹执行时在运行时会发生什么。

当编译fringe left的表达式fringe left ,(1)编译器是否已经知道left树是Branch还是Leaf - 即它只对静态已知的树进行操作 - 或者(2)它是否发出一些if / switch类的条件检查left树是Leaf还是Branch

如果它是后面的ie(2)那么,为什么这应该比等效的C函数更加类型安全,它基本上看起来就像上面那样,只是只有一种类型浮动(指向节点的指针)。

这个:

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):“它发出一些类似case的条件来检查左边的树是Leaf还是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
}

问题是,没有什么t.payload.Branch.leftTree_Leaf案例中无意中使用t.payload.Branch.left等等。 此外,没有任何东西可以静静地阻止你做类似的事情

t.tag = Tree_Branch;
t.payload.Leaf.x = 42;

这会导致“类型” Tree值无效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM