Проблема полупредиката

редактировать

В компьютерном программировании проблема полупредиката возникает, когда подпрограмма , предназначенный для возврата полезного значения, может завершиться ошибкой, но для сигнализации отказа используется в противном случае допустимое возвращаемое значение . Проблема в том, что вызывающий подпрограмму не может сказать, что означает результат в этом случае.

Содержание

  • 1 Пример
  • 2 Практическое значение
  • 3 Решения
    • 3.1 Использование пользовательского соглашения для интерпретации возвращаемых значений
    • 3.2 Многозначный возврат
    • 3.3 Глобальная переменная для статуса возврата
    • 3.4 Исключения
    • 3.5 Расширение типа возвращаемого значения
      • 3.5.1 Созданные вручную гибридные типы
      • 3.5.2 Обнуляемые ссылочные типы
      • 3.5.3 Неявно гибридные типы
      • 3.5.4 Явно гибридные типы
  • 4 См. Также
  • 5 Ссылки

Пример

Операция деления дает действительное число, но не выполняется, когда делитель ноль. Если бы мы должны были написать функцию, которая выполняет деление, мы могли бы выбрать возврат 0 для этого недопустимого ввода. Однако, если дивиденд равен 0, результат тоже будет 0. Это означает, что не существует числа, которое мы можем вернуть, чтобы однозначно сигнализировать о попытке деления на ноль, поскольку все действительные числа находятся в диапазоне деления.

Практическое значение

Ранние программисты имели дело с потенциально исключительными случаями, как и в случае деления, используя соглашение , которое требовало от вызывающей процедуры проверки правильности входных данных. перед вызовом функции деления. У этого были две проблемы. Во-первых, он сильно загромождает весь код, выполняющий деление (очень распространенная операция). Во-вторых, он нарушает принципы Не повторяйтесь и инкапсуляция, где первый касается устранения дублированного кода, а второй предполагает, что код, связанный с данными, должен содержаться в одном месте ( в этом случае проверка ввода проводилась отдельно). Если мы представим себе более сложное вычисление, чем деление, вызывающему может быть сложно узнать, что считается недопустимым вводом; в некоторых случаях выяснение того, является ли ввод действительным, может быть столь же затратным, как выполнение всего вычисления, также существует возможность изменения целевой функции, а затем ожидание других предварительных условий, чем те, которые проверил вызывающий, такое изменение потребует изменений во всех местах, откуда вызывалась функция.

Решения

Проблема полупредиката не универсальна среди функций, которые могут дать сбой.

Использование пользовательского соглашения для интерпретации возвращаемых значений

Если диапазон функции не охватывает весь тип данных, определенный для функции, значение, как известно, невозможно при нормальном вычисление может быть использовано. Например, рассмотрим функцию index, которая принимает строку и подстроку и возвращает integer индекс подстроки в основной строке. Если поиск завершился неудачно, функция может быть запрограммирована на возврат -32 768 (или любое другое отрицательное значение), поскольку это никогда не может означать успешный результат.

У этого решения есть свои проблемы, поскольку оно перегружает естественный смысл функции произвольным соглашением.

  • программист должен помнить конкретные значения отказов для многих функций, которые, конечно, не могут быть идентичными, если функции имеют разные домены.
  • другая реализация одной и той же функции может выбрать использование другое значение ошибки, приводящее к возможным ошибкам при переходе программистов из среды в среду.
  • если сбойная функция хочет сообщить полезную информацию о том, почему она потерпела неудачу, одного значения ошибки недостаточно.
  • целое число со знаком вдвое сокращает возможный диапазон индексов, чтобы иметь возможность хранить знаковый бит .
  • , в то время как дозорный является «недопустимым результатом» для этой операции, он может быть допустимым вводом для последующих операций, например в Python str.findвозвращает -1, если подстрока не найдена, но -1 является допустимым индексом (отрицательные индексы обычно начинаются с конца).

Многозначный возврат

Многие языки позволяют с помощью того или иного механизма функция возвращать несколько значений. Если это доступно, функция может быть перепроектирована так, чтобы возвращать логическое значение, сигнализирующее об успехе или неудаче, в дополнение к своему первичному возвращаемому значению. Если возможны несколько режимов ошибки, функция может вместо этого вернуть перечислимый код возврата (код ошибки) в дополнение к своему первичному возвращаемому значению.

Различные методы возврата нескольких значений включают:

  • Возврат кортежа значений. Это обычное явление для таких языков, как Python, которые имеют встроенный тип данных кортеж и специальный синтаксис для их обработки: в Python x, y = f () вызывает функцию f, которая возвращает пару значений и присваивает элементы пары двум переменным.
  • Вторичные возвращаемые значения, как в Common Lisp. Все выражения имеют первичное значение, но вторичные значения могут быть возвращены заинтересованным вызывающим абонентам. Например, функция GETHASHвозвращает значение данного ключа в ассоциативной карте или значение по умолчанию в противном случае. Однако он также возвращает вторичное логическое значение, указывающее, было ли значение найдено, что позволяет различать случаи «значение не найдено» и «найденное значение равно значению по умолчанию». Это отличается от возврата кортежа, поскольку вторичные возвращаемые значения являются необязательными - если вызывающий не заботится о них, он может полностью их игнорировать, тогда как возвращаемые значения кортежа - это просто синтаксический сахар для возврата и распаковки список, и каждый вызывающий должен всегда знать и использовать все возвращенные элементы.
  • Языки с вызывают по ссылке - или эквиваленты, такие как вызывают по адресу с использованием указатели - могут допускать многозначный возврат, определяя некоторые параметры как выходные параметры. В этом случае функция могла бы просто вернуть значение ошибки с переменной, предназначенной для хранения фактического результата, передаваемого в функцию. Это аналогично использованию статуса выхода для хранения кода ошибки и потоков для возврата контента.
  • В <2 используется вариант выходных параметров.>объектно-ориентированные языки, использующие вызов путем совместного использования, где изменяемый объект передается в функцию, а объект мутируется для возврата значений.
  • языки программирования логики, такие как Пролог даже не имеет возвращаемых значений. Вместо этого в качестве выходных параметров используются несвязанные логические переменные для унификации со значениями, созданными в вызове предиката.

Глобальная переменная для статуса возврата

Аналогично аргументу «out», глобальная переменная может хранить, какая ошибка произошла (или просто произошла ли ошибка).

Например, если возникает ошибка и сигнализируется (обычно, как указано выше, с помощью недопустимого значения, например -1), переменная Unix errno устанавливается для указания какое значение произошло. Использование глобального имеет свои обычные недостатки: безопасность потоков становится проблемой (современные операционные системы используют поточно-ориентированную версию errno), и если используется только одна глобальная ошибка, ее тип должен быть достаточно широким, чтобы содержать вся интересная информация обо всех возможных ошибках в системе.

Исключения

Исключения - одна из широко используемых схем решения этой проблемы. Состояние ошибки вообще не считается возвращаемым значением функции; нормальный поток управления прерывается, и явная обработка ошибки происходит автоматически. Они являются примером внеполосной сигнализации.

Расширение типа возвращаемого значения

Гибридные типы, созданные вручную

В C, общий подход, по возможности, намеренно использовать тип данных шире, чем это строго необходимо функции. Например, стандартная функция getchar ()определяется с типом возвращаемого значения intи возвращает беззнаковый символ в случае успеха или значение EOF(реализация- определено, но вне диапазона [0, 255]) в конце ввода или при ошибке чтения.

Обнуляемые ссылочные типы

В языках с указателями или ссылками одно из решений - вернуть указатель на значение, а не само значение. Затем для этого указателя возврата можно установить значение null, чтобы указать на ошибку. Обычно он подходит для функций, которые в любом случае возвращают указатель, он имеет преимущество в производительности по сравнению со стилем обработки исключений ООП, с недостатком, заключающимся в том, что небрежные программисты могут не проверять возвращаемое значение, что приводит к сбою при недопустимом используется указатель. Распространенным шаблоном в среде UNIX является установка отдельной переменной для указания причины ошибки. Примером этого является функция стандартной библиотеки C fopen () [2].

Неявно гибридные типы

В языках сценариев, таких как PHP и Lisp, обычно возвращается " false »,« none »или« null »при сбое вызова функции. Это работает путем возврата другого типа к нормальному типу возвращаемого значения (таким образом, расширяя тип). Это эквивалент с динамической типизацией возврата нулевого указателя.

Например, числовая функция обычно возвращает число (int или float), а ноль может быть допустимым ответом; ложь нет. Точно так же функция, которая обычно возвращает строку, может иногда возвращать пустую строку в качестве действительного ответа, но возвращать ложь при ошибке. Этот процесс манипулирования типами требует осторожности при тестировании возвращаемого значения: например, в PHP используйте === [т.е. равны и одного типа], а не просто == [т.е. равно, после автоматического преобразования типов]. Он работает только в том случае, если исходная функция не предназначена для возврата логического значения и по-прежнему требует, чтобы информация об ошибке передавалась другими способами.

Явно гибридные типы

В Haskell и других языках функционального программирования обычно используются типы данных, размер которых не превышает его размера. должен выражать любой возможный результат. Например, мы могли бы написать функция деления, которая вернула тип Maybe Real, и функция getchar, возвращающая Either String Char. Первый - это вариант типа, который имеет только одно значение ошибки, Ничего. Второй случай - это объединение с тегами : результатом является либо некоторая строка с описательным сообщением об ошибке, либо успешно прочитанный символ. Система вывода типа в Haskell помогает гарантировать, что вызывающая сторона имеет дело с возможными ошибками. Поскольку условия ошибки становятся явными в типе функции, взгляд на ее сигнатуру сразу же подсказывает программисту, как обрабатывать ошибки. Кроме того, помеченные объединения и типы параметров образуют монады, когда наделены соответствующими функциями: это может использоваться для поддержания порядка в коде путем автоматического распространения необработанных условий ошибки.

См. Также

Ссылки

  1. ^Norvig, Peter (1992), «Решение общих проблем», Парадигмы программирования искусственного интеллекта: тематические исследования в общем LISP (3-е изд.), Морган Кауфманн, стр. 127; 946, ISBN 1-55860-191-0
  2. ^[1]
  3. ^«Если i или j отрицательны, индекс отсчитывается относительно конца последовательности s: len (s) + iили len (s) + jзаменяется. "примечание операций общей последовательности (3)
  4. ^Почему исключения должны быть исключительными - пример сравнения производительности
Последняя правка сделана 2021-06-07 09:48:37
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте