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

Jon*_*her 3 c haskell types algebraic-data-types data-structures

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

data No = NO
Run Code Online (Sandbox Code Playgroud)

NO没有任何解释作为数字.如果我们在C中有相同的东西,那么我们就可以做到

union MaybeInt { enum No no; int just;};
Run Code Online (Sandbox Code Playgroud)

这可以用来做一些事情,比如有一个初始化为No的数组.

int A[k];
for (int i = 0; i < k; i++)
    A[i] = NO;
Run Code Online (Sandbox Code Playgroud)

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

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

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

使用枚举类型的问题:我看到的第一件事,就是让我跳出座位说"是"是枚举类型.我想为什么不做类似enum No {no}; 嘛,用nos 初始化用于memoization的数组有问题.如果我喜欢的话,问题是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);
Run Code Online (Sandbox Code Playgroud)

如果在C中存在某种不相交的联合类型,那么最好的是,如果我使用了联合的一个值,则另一个变得无法获得.

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

disjoint T {type1 name1 , .... };
Run Code Online (Sandbox Code Playgroud)

如果设置了T.name2,则对T.name1的引用会引发错误.或者甚至更好地提及T必须经过某种区分.

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

Ker*_* SB 10

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

struct Data
{
    enum DataType
    {
        NotSet,
        Integer,
        Infinity,
        Message
    } tag;
    union ValueType
    {
        int n;
        char const * msg;
    } data;
};
Run Code Online (Sandbox Code Playgroud)

现在您只需要维护标记规则,即只读取适合给定标记的值,并在写入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;
}
Run Code Online (Sandbox Code Playgroud)

  • @JonathanGallagher ANSI C不支持您正在寻找的抽象级别.您可以创建一个C文件和标题,它将实现ADT作为包含标记字段和数据字段的结构,如Kerrek所示,您甚至可以通过限制头文件提供的内容来阻止人们对结构进行破坏.一个不透明的指针和一些函数(一个智能构造函数).但是,人们仍然能够执行基于指针的内存操作(除其他外,由于C的弱键入). (5认同)