반보편적 문제

Semipredicate problem

컴퓨터 프로그래밍에서, 유용한 값을 반환하기 위한 서브루틴이 실패할 수 있지만, 실패의 신호는 다른 유효한 반환 값을 사용할 때 반제곱 문제가 발생한다.[1]문제는 서브루틴을 호출한 사람이 이 경우 결과가 무엇을 의미하는지 알 수 없다는 점이다.

분할 작업은 실제 숫자를 산출하지만 분할자가 0일 때 실패한다.만약 우리가 분할을 수행하는 함수를 쓴다면, 우리는 이 잘못된 입력에 대해 0을 반환하는 것을 선택할 수 있을 것이다.그러나 배당금이 0이면 결과도 0이다.이는 모든 실제 숫자가 분할 범위에 있기 때문에 0으로 분할 시도된 고유 신호로 되돌릴 수 없다는 것을 의미한다.

실제적 함의

초기 프로그래머들은 분할 기능을 호출하기 전에 입력의 유효성을 확인하기 위해 호출 루틴을 필요로 하는 규약을 사용하여 분할의 경우와 마찬가지로 잠재적으로 예외적인 경우를 다루었다.이것은 두 가지 문제가 있었다.첫째, 분할을 수행하는 모든 코드(매우 일반적인 연산)를 크게 인코딩한다.둘째, 중복된 코드를 제거하는 것이 전자의 경우, 데이터 관련 코드를 한 곳에 담아야 한다고 제안하는 Don't repeat 원칙과 캡슐화 원칙을 위반한다(이 경우 입력 검증은 별도로 수행되었다).만약 우리가 분할보다 더 복잡한 계산을 상상한다면, 발신자가 잘못된 입력으로 간주되는 것을 아는 것은 어려울 수 있다; 어떤 경우에는 입력의 유효성을 알아내는 것이 전체 계산을 수행하는 것만큼 비용이 많이 들 수도 있다. 또한, 표적 기능이 수정되어 다른 프리콘디티를 기대할 가능성도 있다.발신자가 확인한 것보다 변경하면 해당 기능이 호출된 모든 위치에서 변경해야 한다.

해결 방법

반보정 문제는 실패할 수 있는 함수들 사이에서 보편적이지 않다.

사용자 정의 규칙을 사용하여 반환 값 해석

함수의 범위가 함수에 대해 정의된 전체 데이터 유형을 포함하지 않는 경우, 정상 연산에서는 불가능하다고 알려진 값을 사용할 수 있다.예를 들어, 함수를 고려하십시오.index문자열과 하위 문자열을 사용하고, 주 문자열에 있는 하위 문자열의 정수 색인을 반환합니다.검색이 실패하면, 함수는 -32,768(또는 다른 음수 값)을 반환하도록 프로그래밍될 수 있는데, 이는 결코 성공적인 결과를 나타낼 수 없기 때문이다.

그러나 이 해결책은 함수의 자연적 의미를 임의적 관습으로 과부하하기 때문에 문제가 있다.

  • 프로그래머는 많은 기능들에 대한 구체적인 고장 값을 기억해야 하며, 기능들이 서로 다른 도메인을 가지고 있다면 물론 동일할 수 없다.
  • 동일한 기능의 다른 구현은 프로그래머가 환경에서 환경으로 이동할 때 버그가 발생할 수 있도록 다른 고장 값을 사용하도록 선택할 수 있다.
  • 만일 고장난 함수가 왜 실패했는지에 대한 유용한 정보를 전달하고자 한다면, 하나의 고장 값은 불충분하다.
  • 부호화된 정수는 부호 비트를 저장할 수 있는 가능한 인덱스 범위를 절반으로 나눈다.
  • 선택한 값이 이 작업에 대한 잘못된 결과지만 후속 작업에 대한 유효한 입력일 수 있다.예: Pythonstr.find하위 문자열이 발견되지 [2]않는 경우 -1을 반환하지만 -1은 유효한 지수(음수 지수는 일반적으로 끝에서[3] 시작됨)이다.

다중값 반환

많은 언어가 하나의 메커니즘이나 다른 메커니즘을 통해 여러 값을 반환하는 함수를 허용한다.이것이 가능하다면, 함수는 기본 반환 값 외에 부울 값 신호의 성공 또는 실패를 반환하도록 재설계될 수 있다.다중 오류 모드가 가능한 경우 함수는 기본 반환 값 외에 열거된 반환 코드(오류 코드)를 대신 반환할 수 있다.

복수 값을 반환하는 다양한 기법은 다음과 같다.

  • 값의 튜플 반환.이는 Python과 같은 언어에서 일반적인 것으로, 튜플 데이터 유형이 내장되어 있고, 이를 처리하기 위한 특별한 구문이 있다: Python에서는,x, y = f()은 값 쌍을 반환하고 쌍의 요소를 두 변수에 할당하는 함수 f를 호출한다.
  • Common Lisp과 같은 보조 반환 값.모든 표현식은 1차 값을 가지지만 2차 값은 관심 있는 호출자에게 반환될 수 있다.예를 들어,GETHASH함수는 연관 지도에서 지정된 키의 값을 반환하거나, 그렇지 않으면 기본값을 반환한다.그러나 값이 발견되었는지 여부를 나타내는 2차 부울도 반환하여 "No value found" 사례와 "no value was been default" 사례를 구분할 수 있다.이는 2차 반환 값이 선택적이라는 점에서 튜플을 반환하는 것과 다르다. 즉, 발신자가 상관하지 않을 경우 튜플 값을 완전히 무시할 수 있는 반면, 튜플 값 반환은 목록을 반환하고 압축을 푸는 통사당일 뿐이며, 모든 발신자는 반환된 모든 항목에 대해 항상 알고 소비해야 한다.
  • 참조에 의한 호출(: 포인터를 사용한 주소별 호출)이 있는 언어는 일부 파라미터를 출력 파라미터로 지정하여 다중값 반환을 허용할 수 있다.이 경우 함수는 실제 결과를 함수에 전달하기 위한 변수를 저장하기 위해 오류 값만 반환할 수 있다.는 종료 상태를 사용하여 오류 코드를 저장하고 콘텐츠를 반환하는 스트림을 사용하는 것과 유사하다.
  • 공유에 의한 호출을 사용하는 객체지향 언어에서는 변이 가능한 객체가 함수에 전달되고 객체가 변이되어 값을 반환하는 객체지향 언어에 출력 매개변수의 변형이 사용된다.
  • Prolog와 같은 논리 프로그래밍 언어에는 반환 값이 없다.대신, 결합되지 않은 논리 변수는 술어 호출에서 생성된 값과 통일되도록 출력 매개변수로 사용된다.

반환 상태에 대한 전역 변수

전역 변수는 "out" 인수와 유사하게 발생한 오류(또는 단순히 오류가 발생했는지 여부)를 저장할 수 있다.

예를 들어, 오류가 발생하여 (일반적으로 위와 같이 -1과 같은 잘못된 값으로) 유닉스errno변수는 어떤 값이 발생했는지 나타내기 위해 설정된다.글로벌 사용에는 일반적인 단점이 있다: 스레드 안전이 문제가 되며(현대 운영 체제는 스레드 세이프 버전의 에러를 사용함), 글로벌을 하나만 사용할 경우 시스템의 모든 가능한 오류에 대한 모든 흥미로운 정보를 포함할 수 있을 만큼 충분히 넓은 유형이어야 한다.

예외

예외는 이 문제를 해결하기 위해 널리 사용되는 하나의 계획이다.오류 조건은 기능의 반환 값으로 전혀 간주되지 않는다. 정상적인 제어 흐름은 중단되고 오류의 명시적 처리가 자동으로 이루어진다.그들은 대역신호 전달의 한 예다.

반환 값 유형 확장

수동으로 생성한 하이브리드 유형

C에서, 가능한 한 공통적인 접근방식은 기능에 의해 엄격히 필요한 것보다 의도적으로 더 넓은 데이터 유형을 사용하는 것이다.예를 들어, 표준 함수getchar()반환 유형으로 정의됨int그리고 [0,10] 범위의 값을 반환한다(의 범위unsigned char성공 또는 가치에 대해EOF(정확히 정의되었지만, 이 범위에서는 벗어남)unsigned char입력의 끝 또는 읽기 오류에 표시.

무효 참조 유형

포인터나 참조가 있는 언어에서 하나의 해결책은 값 자체보다는 값으로 포인터를 반환하는 것이다.그런 다음 이 반환 포인터를 null로 설정하여 오류를 나타낼 수 있다.그것은 어쨌든 포인터를 반환하는 기능에 일반적으로 적합하다.이는 예외 처리의 OOP 스타일에 비해 성능상 이점이 있는데,[4] 이는 부주의한 프로그래머가 반환값을 확인하지 못해 유효하지 않은 포인터를 사용했을 때 충돌이 발생할 수 있다는 단점이 있다.UNIX 환경의 일반적인 패턴은 오류의 원인을 나타내기 위해 별도의 변수를 설정하는 것이다.이것의 로는 C 표준 라이브러리가 있다. fopen()기능을 발휘하다

암시적 하이브리드 유형

PHP, Lisp와 같이 동적으로 타이핑된 언어에서는 함수 호출이 실패할 때 "false", "none" 또는 "null"을 반환하는 것이 일반적인 접근 방식이다.이는 다른 유형을 일반 반환 유형(즉, 유형을 확장하는 유형)으로 되돌리는 방식으로 작동한다.그것은 동적으로 null 포인터를 반환하는 것과 같다.

예를 들어 숫자 함수는 일반적으로 숫자(int 또는 float)를 반환하며 0은 유효한 응답일 수 있지만 false는 그렇지 않다.마찬가지로, 일반적으로 문자열을 반환하는 함수는 때때로 빈 문자열을 유효한 응답으로 반환하지만 실패 시 거짓으로 반환할 수 있다.이러한 유형의 주글링 프로세스에서는 반환 값 테스트에 주의를 기울여야 한다(예: PHP, 사용).===(즉, 동일하고 동일한 유형의) 단순한 것이 아니라==(즉, 자동 형식 지정 후 동일).원래 함수가 부울 값을 반환하지 않을 때만 작동하며, 여전히 오류에 대한 정보를 다른 수단을 통해 전달해야 한다.

명시적으로 혼합 유형

Haskell다른 기능 프로그래밍 언어에서는 가능한 결과를 표현하기 위해 필요한 만큼 큰 데이터 유형을 사용하는 것이 일반적이다.예를 들어, 유형을 반환하는 분할 함수를 작성할 수 있다.Maybe Real, 그리고 agetchar반환 기능을 하다Either String Char첫 번째는 옵션 유형으로 고장 값이 하나뿐입니다.Nothing. 두 번째 경우는 태그가 붙은 조합이다. 결과는 서술적 오류 메시지가 있는 문자열 또는 성공적으로 읽은 문자열을 말한다.하스켈의 유형추론 시스템은 발신자가 발생할 수 있는 오류를 처리하도록 돕는다.기능 유형에서 에러 조건이 명시적이기 때문에, 그것의 서명을 보면 프로그래머에게 에러를 처리하는 방법을 즉시 알려준다.또한 태그가 붙은 조합과 옵션 유형은 적절한 기능이 부여된 경우 모노드를 형성한다. 이는 처리되지 않은 오류 조건을 자동으로 전파하여 코드를 깔끔하게 유지하는 데 사용될 수 있다.

참고 항목

참조

  1. ^ Norvig, Peter (1992). "The General Problem Solver". Paradigms of artificial intelligence programming: case studies in common LISP. Morgan Kaufmann. p. 127. ISBN 1-55860-191-0.
  2. ^ https://docs.python.org/3/library/stdtypes.html#str.find
  3. ^ "i 또는 j가 음수일 경우, 지수는 시퀀스 s의 끝에 상대적이다.len(s) + i또는len(s) + j대체되다"공통 시퀀스 작업 노트 (3)
  4. ^ 예외가 예외여야 하는 이유 - 성능 비교의 예