public static IBooleanFunction ExecuteRecursive(IBooleanFunction booleanFunction, TryTransformHandler tryTransform)
        {
            switch (booleanFunction)
            {
            case InputFunction inputFunction: return(inputFunction);

            case NotFunction notFunction:
                var argumentTransformed = ExecuteRecursive(notFunction.Argument, tryTransform);
                var internals           = NotFunction.NotOptimized(argumentTransformed);
                if (tryTransform(internals, out IBooleanFunction internalsFullyTransformed))
                {
                    return(internalsFullyTransformed);
                }
                else
                {
                    return(internals);
                }

            case AndFunction andFunction:
                var andItemsTransformed = new List <IBooleanFunction>();
                foreach (var item in andFunction.Items)
                {
                    var itemTransformed = ExecuteRecursive(item, tryTransform);
                    andItemsTransformed.Add(itemTransformed);
                }
                return(new AndFunction(andItemsTransformed));

            case OrFunction orFunction:
                var orItemsTransformed = new List <IBooleanFunction>();
                foreach (var item in orFunction.Items)
                {
                    var itemTransformed = ExecuteRecursive(item, tryTransform);
                    orItemsTransformed.Add(itemTransformed);
                }
                return(new OrFunction(orItemsTransformed));

            default: throw new NotSupportedException();
            }
        }
        public static bool TryConvertNotOfAndToOrOfNot(
            IBooleanFunction boolFunction, out IBooleanFunction result)
        {
            result = null;

            if (!(boolFunction is NotFunction))
            {
                return(false);
            }

            NotFunction root = (NotFunction)boolFunction;

            if (!(root.Argument is AndFunction))
            {
                return(false);
            }

            AndFunction andFunction = (AndFunction)root.Argument;

            result = new OrFunction(
                andFunction.Items.Select(NotFunction.NotOptimized)
                );
            return(true);
        }