Отказ от ответственности: я программист на Haskell, изучаю C. В 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
s. Проблема в том, что no
определяется как 0
или какая-то числовая константа по моему выбору, если мне нравится. Это неудовлетворительно, потому что, если значение, хранящееся в массиве, предполагается равным нулю (или той константе по моему выбору), то, когда я выполняю проверку, A[i] == no
может быть так и должно быть! Таким образом, я в конечном итоге выполню ненужную рекурсию.
Это подводит нас к вопросу 1: как я могу получить символическую константу в C, которая обрабатывается как флаг, несравнимая ни с чем другим типом?
Теперь проблема с профсоюзами. Объединение хранит все свои поля в одном единственном адресе. Так, например, обновление mayInt.just влияет на значение mayInt.no. Например,
union MaybeInt maybeInt;
maybeInt.just=9;
printf("%d",maybeInt.just);
printf("%d",maybeInt.no);
печатает 99. Было бы неплохо, если бы в C существовал какой-то непересекающийся тип объединения, так что если бы я использовал одно из значений объединения, другое стало бы недоступным.
Это подводит нас ко второму и последнему вопросу: как можно получить тип несвязного объединения в C — это тип, который имеет много возможных вариантов, но только один в любой момент времени. Я хотел бы, чтобы что-то можно было сделать что-то вроде:
disjoint T {type1 name1 , .... };
и если установлен T.name2, то ссылка на T.name1 выдает ошибку. Или, что еще лучше, любая ссылка на T должна пройти какое-то различие в падежах.
Если это невозможно сделать красиво, пожалуйста, объясните, почему.