C符号类型和不相交的联合类型?

时间:2013-09-24 21:59:23

标签: c haskell data-structures types algebraic-data-types

免责声明:我是一名学习C的Haskell程序员。在Haskell中,我们有数据声明,如

data No = NO

其中NO没有任何解释作为数字。如果我们在C中有相同的东西,我们可以做

union MaybeInt { enum No no; int just;};

可用于执行诸如将数组初始化为No的数据。

int A[k];
for (int i = 0; i < k; i++)
    A[i] = NO;

这在进行记忆时非常有用,因为通常会有一些重新算法算法在数组中查找并根据查找的值,或者进行递归调用。例如:(对于斐波那契数字)

fibMem (int k){
    if (FIB[k] == NO)
      compute fibMem(k-1) + fib(k-2) and store the result in FIB[k]
    return FIB[k]
}

现在,当然,我可以将FIB [i]初始化为一些荒谬的值,如-100,这适用于这个问题;但是,鉴于一个任意的记忆例程,我不知道值的范围,这种解决方案是行不通的。

使用枚举类型的问题:我看到的第一件事,就是让我跳出座位说“是”是枚举类型。我想为什么不做enum No {no};之类的事情嗯,用no初始化用于记忆的数组有问题。问题是如果我愿意,no被定义为0或我选择的某个数字常量。这是不能令人满意的,因为如果存储在数组中的值假设为零(或我选择的常量),那么当我执行检查A[i] == no时,它可能应该是办法!因此,我最终会执行一个不需要的递归。

这给我们带来了问题1:如何在C中获得一个被视为标志的符号常量,这对于任何不同类型的东西都是无法比拟的?

现在,工会的问题。联盟将其所有字段存储在一个地址中。因此,例如,对maybeInt.just的更新会影响maybeInt.no的值。例如,

union MaybeInt maybeInt;
maybeInt.just=9;
printf("%d",maybeInt.just);
printf("%d",maybeInt.no);

打印99.如果在C中存在某种不相交的联合类型,那将会很好,所以如果我使用了联合的一个值,则另一个变得无法获得。

这给我们带来了第二个也是最后一个问题:如何在C中获得不相交的联合类型 - 这是一种具有许多可能变体的类型,但在任​​何给定时间只有一个。我希望能够做一些事情:

disjoint T {type1 name1 , .... };

并设置if T.name2,然后对T.name1的引用会引发错误。或者更好的是,对T的任何引用都必须经过某种区分。

如果不能很好地完成,请解释原因。

1 个答案:

答案 0 :(得分:10)

受歧视的工会是一种非常标准的C语言。您只需将标记与数据分开:

struct Data
{
    enum DataType
    {
        NotSet,
        Integer,
        Infinity,
        Message
    } tag;
    union ValueType
    {
        int n;
        char const * msg;
    } data;
};

现在您只需要维护标记规则,即只读取适合给定标记的值,并在写入union成员后更新标记。例如:

void foo(struct Data const * x)
{
    switch (x->tag)
    {
    case NotSet:      // ...
    case Integer:     // use x->data.n
    case Infinity:    // ...
    case Message:     // use x->data.msg
    };

    x->data.msg = "Thank you!";
    x->tag = Message;
}