recursive datatypes in haskell

时间:2017-04-10 01:24:18

标签: c pointers haskell type-safety algebraic-data-types

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).

1 个答案:

答案 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