동적 절 관리

동적 절 관리

동적(dynamic) 프로시저의 절을 추가·제거·검사하는 술어들을 설명해요.

출처: GNU Prolog Manual - Dynamic clause management

본문

소개

정적 및 동적 프로시저: 프로시저는 동적이거나 정적이에요. 모든 내장 술어는 정적이에요. 사용자 정의 프로시저는 그 정의 앞에 dynamic/1 지시자(7.1.2절)가 있지 않으면 기본적으로 정적이에요. 존재하지 않는 프로시저에 절을 추가하면 동적 프로시저가 만들어져요. 동적 프로시저의 절은 변경할 수 있어요(예: asserta/1 사용), 정적 프로시저의 절은 변경할 수 없어요.

비공개 및 공개 프로시저: 각 프로시저는 공개(public)이거나 비공개(private)예요. 동적 프로시저는 항상 공개예요. 모든 내장 술어는 비공개이며, 정적 사용자 정의 프로시저는 그 정의 앞에 public/1 지시자(7.1.3절)가 있지 않으면 기본적으로 비공개예요. 동적 선언이 존재하면 public 선언을 추가할 필요가 없어요. 동적 프로시저는 공개이기 때문이에요. 공개 프로시저의 절은 검사할 수 있어요(예: clause/2 사용), 비공개 프로시저의 절은 검사할 수 없어요.

논리적 데이터베이스 갱신 관점: 목표를 실행한 결과로 발생하는 데이터베이스의 어떤 변경(예: 하위 목표가 assertz/1 또는 retract/1의 호출일 때)은 이후의 활성화에만 영향을 줘요. 그 변경은 현재 실행 중인 어떤 활성화에도 영향을 주지 않아요. 따라서 목표 실행 중 데이터베이스는 동결되고, 술어를 정의하는 절의 목록은 그 실행 순간에 고정돼요.

asserta/1, assertz/1

Templates

asserta(+clause)
assertz(+clause)

Description asserta(Clause)는 먼저 항 Clause를 절로 변환한 다음 현재 내부 데이터베이스에 추가해요. 관련 술어는 동적(8.7.1절)이거나 정의되지 않아야 하며, 절은 술어의 첫 번째 절 앞에 삽입돼요. 술어가 정의되지 않았다면 동적 프로시저로 생성돼요.

assertz(Clause)는 관련 술어의 모든 기존 절 끝에 절이 추가된다는 점만 제외하면 asserta/1처럼 동작해요.

항 Clause를 절 Clause1로 변환:

  1. Clause의 머리와 본문을 추출: Clause = (Head :- Body) 또는 Clause = Head이고 Body = true.
  2. Head는 callable 항이어야 함(그렇지 않으면 변환 실패).
  3. Body를 본문 절(즉 목표) Body1로 변환.
  4. 변환된 절 Clause1 = (Head :- Body1).

항 T를 목표로 변환:

  • T가 변수이면 call(T) 항으로 대체.
  • T가 제어 구조(','/2, ;/2, ->/2)이면 제어 구조의 각 인자를 재귀적으로 목표로 변환.
  • T가 callable 항이면 그대로 유지.
  • 그렇지 않으면 변환 실패(T가 변수도 callable 항도 아님).

Errors

  • Head가 변수 - instantiation_error
  • Head가 변수도 callable 항도 아님 - type_error(callable, Head)
  • Body를 목표로 변환할 수 없음 - type_error(callable, Body)
  • Head의 술어 표시자 Pred가 정적 프로시저의 것임 - permission_error(modify, static_procedure, Pred)

Portability: ISO 술어.

retract/1

Templates

retract(+clause)

Description retract(Clause)Clause와 통일되는 데이터베이스의 첫 번째 절을 지워요. 관련 술어는 동적 프로시저(8.7.1절)여야 해요. 프로시저의 모든 절을 제거해도 프로시저 정의는 지워지지 않아요. 이를 달성하려면 abolish/1(8.7.6절)을 사용해요. retract/1는 백트래킹 시 재실행 가능해요.

Errors

  • Head가 변수 - instantiation_error
  • Head가 변수도 callable 항도 아님 - type_error(callable, Head)
  • Head의 술어 표시자 Pred가 정적 프로시저의 것임 - permission_error(modify, static_procedure, Pred)

Portability: ISO 술어. ISO 참조에서 permission_error와 연관된 연산은 access이지만 GNU Prolog에서는 modify예요. asserta/1(retract/1과 취지가 비슷한)의 경우 연산도 modify이므로 이것은 ISO 참조의 오류로 보여요.

retractall/1

Templates

retractall(+head)

Description retractall(Head)는 머리가 Head와 통일되는 모든 절을 지워요. 관련 술어는 동적 프로시저(8.7.1절)여야 해요. 프로시저 정의는 제거되지 않으므로 current_predicate/1(8.8.1절)로 찾을 수 있어요. 프로시저를 제거하려면 abolish/1을 사용해야 해요(8.7.6절).

Errors

  • Head가 변수 - instantiation_error
  • Head가 callable 항이 아님 - type_error(callable, Head)
  • Head의 술어 표시자 Pred가 정적 프로시저의 것임 - permission_error(modify, static_procedure, Pred)

Portability: ISO 술어.

clause/2

Templates

clause(+head, ?callable_term)

Description clause(Head, Body)는 데이터베이스에 Head :- Body와 통일되는 절이 있으면 성공해요. 해당 술어는 공개 프로시저(8.7.1절)여야 해요. 절은 첫 번째부터 마지막까지 전달돼요. 이 술어는 백트래킹 시 재실행 가능해요.

Errors

  • Head가 변수 - instantiation_error
  • Head가 변수도 callable 항도 아님 - type_error(callable, Head)
  • Head의 술어 표시자 Pred가 비공개 프로시저의 것임 - permission_error(access, private_procedure, Pred)
  • Body가 변수도 callable 항도 아님 - type_error(callable, Body)

Portability: ISO 술어.

abolish/1

Templates

abolish(+predicate_indicator)

Description abolish(Pred)는 술어 표시자가 Pred인 프로시저를 데이터베이스에서 제거해요. 관련 술어는 동적 프로시저(8.7.1절)여야 해요.

Errors

  • Pred가 변수 - instantiation_error
  • PredName/Arity 항이고 Name 또는 Arity가 변수 - instantiation_error
  • Pred가 변수도 술어 표시자도 아님 - type_error(predicate_indicator, Pred)
  • PredName/Arity 항이고 Arity가 변수도 정수도 아님 - type_error(integer, Arity)
  • PredName/Arity 항이고 Name이 변수도 원자도 아님 - type_error(atom, Name)
  • PredName/Arity 항이고 Arity가 정수 < 0 - domain_error(not_less_than_zero, Arity)
  • PredName/Arity 항이고 Aritymax_arity 플래그(8.22.1절)보다 큰 정수 - representation_error(max_arity)
  • 술어 표시자 Pred가 정적 프로시저의 것임 - permission_error(modify, static_procedure, Pred)

Portability: ISO 술어.

더 알아보기