Все теории множеств, о которых я читал, мне не нравились по разным причинам, но в основном из-за того, что у них были различные типы бесконечностей ( счётная, континуум и т.д. ). Поэтому я решил создать свою теорию с одним типом бесконечности. К тому же появилась идея изложить её при помощи языка С++. Для программистов это будет нагляднее, чем на языке логики. Конечно, это не полная теория, а набор отдельных положений представляющих общую идею.
Введение
Как обычно, мы будем рассматривать множества, элементами которых являются тоже множества, и будем определять их в виде структур языка С++. Структуры были выбраны вместо классов для того, чтобы не путать их с классами теории множеств NBG. Одно множество может быть определено различными структурами. Характеристическую функцию множества будем представлять в структуре оператором (). Общий вид множества задаётся абстрактной структурой Set:
struct Set { virtual bool operator() ( Set & ) = 0; };
Все множества будут производными структурами от неё с реализованным оператором (). Характеристическая функция должна быть определена для всех входных множеств, а значит в ней не должно быть зацикливаний или бесконечных рекурсий. Можно, конечно, рассматривать нечёткие множества, у которых не для всех входных множеств определена характеристическая функция, но здесь мы этого делать не будем.
Некоторые функции
Нам понадобятся следующие функции, которые мы реализовывать не будем, но будет понятно, что они должны делать.
Операторы сравнения множеств:
bool operator == ( Set & s1, Set & s2 ); bool operator != ( Set & s1, Set & s2 );
Подсчёт количества элементов множества ( для бесконечных множеств будем использовать значение -1 ):
int count ( Set & s );
Вернуть указатель на какой-то элемент множества s, если множество непустое, иначе вернуть нулевой указатель:
Set * get_any ( Set & s );
Проверка, является ли множество s подмножеством множества S:
template <typename S> bool isSubset<S> ( Set & s );
Элементарные множества
Есть два самых простых в реализации множества. Это пустое множество:
struct Empty : Set { bool operator() ( Set & ) { return false; } };
И универсальное множество ( множество всех множеств ):
struct Universal : Set { bool operator() ( Set & ) { return true; } };
Назовём эти множества элементарными, а остальные множества будут построены из них при помощи некоторых правил. С точки зрения языка С++ эти правила являются шаблонными типами.
Примеры построения множеств
Множества с одним элементом S:
template <typename S> struct Set1 : Set { bool operator() ( Set & x ) { return x == S(); } };
Множества без одного элемента S:
template <typename S> struct Set_1 : Set { bool operator() ( Set & x ) { return x != S(); } };
Дополнение к множеству S:
template <typename S> struct Dop : Set { bool operator() ( Set & x ) { return ! S() ( x ); } };
Объединение двух множеств:
template < typename S1, typename S2> struct Union : Set { bool operator() ( Set & x ) { return S1() ( x ) || S2() ( x ); } };
Пересечение двух множеств:
template < typename S1, typename S2> struct Inter : Set { bool operator() ( Set & x ) { return S1() ( x ) && S2() ( x ); } };
Структуры Union<A, Union<B,C>> и Union<Union<A, B>,C> задают одно и то же множество. Также, например, Inter<Empty, Universal> и Empty определяют пустое множество. Об этом говорилось в самом начале статьи: одно и то же множество может быть определено различными структурами.
Множество всех подмножеств множества S:
template <typename S> struct Boolean : Set { bool operator() ( Set & x ) { return isSubset<S> ( x ); } };
Натуральные числа
Натуральные числа можно определить следующим образом:
typedef Set1<Empty> N1; typedef Set1<N1> N2; typedef Set1<N2> N3; typedef Set1<N3> N4; ....
Для того, чтобы определить множество всех натуральных чисел воспользуемся следующим шаблоном:
template <typename S> struct Recur : Set { bool operator() ( Set & x ) { return x == S() || ( count ( x ) == 1 && (*this) ( *get_any ( x ) ) ); } };
В структуре Recur оператор () вызывает сам себя и, если бы не было сравнения x == S(), то произошёл бы бесконечный вызов, и значение оператора было бы не определено. Поэтому для того, чтобы не было неопределённостей, нужно следить за тем, чтобы не было зацикливаний.
Парадокс Рассела
Множество Рассела — это множество всех множеств, которые не входят сами в себя. При попытке понять входит ли множество Рассела само в себя возникает парадокс. В наших обозначениях это можно записать так:
struct Russell : Set { bool operator() ( Set & x ) { return ! x ( x ); } };
Теперь, если подставить вместо x само множество Рассела, то получим бесконечную рекурсию. К счастью это множество недопустимо в наших правилах.
Теорема Кантора
В теореме Кантора строится следующее множество. Дано множество А и множество его подмножеств Boolean<A>. Пусть G это отображение элементов А в Boolean<A>. Строим множество, которое логически описывается, как { x ∈ A & x ∉ G[x] }. Тогда в наших обозначениях это будет:
template <typename A, typename G> struct Сantor : Set { bool operator() ( Set & x ) { return A() ( x ) && ! ( G() ( x ) ) ( x ); } };
Теорема Кантора утверждает, что Сantor<A, G> ∉ G[A]. В нашем случае пусть для какого-то х отображение G[x] даст множество Сantor<A, G>, тогда мы получим бесконечную рекурсию, а это значит, что определение множества Кантора является недопустимым. Таким образом вместо доказательства о существовании несчётных множеств получается неправильное определение множества.
Один тип бесконечности
Любое множество — это описание из конечного набора символов на каком-то языке. Эти описания можно упорядочить. В итоге получаем счётное количество множеств. Этот факт давно известен под названием парадокс Скулема. Этот парадокс объясняется тем, что это рассуждение является внешним по отношению к изучаемой теории. Но, на мой взгляд, это означает, что все множества счётны, а континуум и другое были введены для разрешения внутренних противоречий.
ссылка на оригинал статьи https://habr.com/ru/articles/895732/
Добавить комментарий