Dynamic clause management

7.7 | Dynamic clause management

- Introduction
- `asserta/1`, `assertz/1`
- `retract/1`
- `retractall/1`
- `clause/2`
- `abolish/1`

7.7.1 | Introduction

Static and dynamic procedures: a procedure is either dynamic or static. All built-in predicates are static. A user-defined procedure is static by default unless a `dynamic/1` directive precedes its definition (section 6.1.2). Adding a clause to a non-existent procedure creates a dynamic procedure. The clauses of a dynamic procedure can be altered (e.g. using `asserta/1`), the clauses of a static procedure cannot be altered.
Private and public procedures: each procedure is either public or private. A dynamic procedure is always public. Each built-in predicate is private, and a static user-defined procedure is private by default unless a `public/1` directive precedes its definition (section 6.1.3). If a dynamic declaration exists it is unnecessary to add a public declaration since a dynamic procedure is also public. A clause of a public procedure can be inspected (e.g. using `clause/2`), a clause of a private procedure cannot be inspected.
A logical database update view: any change in the database that occurs as the result of executing a goal (e.g. when a sub-goal is a call of `assertz/1` or `retract/1`) only affects subsequent activations. The change does not affect any activation that is currently being executed. Thus the database is frozen during the execution of a goal, and the list of clauses defining a predication is fixed at the moment of its execution.

7.7.2 | `asserta/1`, `assertz/1`

Templates

  `asserta(+clause)
  assertz(+clause)`

Description
`asserta(Clause)` first converts the term `Clause` to a clause and then adds it to the current internal database. The predicate concerned must be dynamic (section 7.7.1) or undefined and the clause is inserted before the first clause of the predicate. If the predicated is undefined it is created as a dynamic procedure.
`assertz(Clause)` acts like `asserta/1` except that the clause is added at the end of all existing clauses of the concerned predicate.
Converting a term `Clause` to a clause `Clause1`:

- extract the head and the body of `Clause`: either `Clause` = `(Head :- Body)` or `Clause` = `Head` and `Body` = `true`.
- `Head` must be a callable term (or else the conversion fails).
- convert `Body` to a body clause (i.e. a goal) `Body1`.
- the converted clause `Clause1` = `(Head :- Body1)`.

Converting a term `T` to a goal:

- if `T` is a variable it is replaced by the term `call(T)`.
- if `T` is a control construct `(',')/2`, `(;)/2` or `(->)/2` each argument of the control construct is recursively converted to a goal.
- if `T` is a callable term it remains unchanged.
- otherwise the conversion fails (`T` is neither a variable nor a callable term).

Errors

`Head` is a variable |  | `instantiation_error`
`Head` is neither a variable nor a callable term |  | `type_error(callable, Head)`
`Body` cannot be converted to a goal |  | `type_error(callable, Body)`
The predicate indicator `Pred` of `Head` is that of a static procedure |  | `permission_error(modify, static_procedure, Pred)`

Portability
ISO predicates.

7.7.3 | `retract/1`

Templates

  `retract(+clause)`

Description
`retract(Clause)` erases the first clause of the database that unifies with `Clause`. The concerned predicate must be a dynamic procedure (section 7.7.1). Removing all clauses of a procedure does not erase the procedure definition. To achieve this use `abolish/1` (section 7.7.6). `retract/1` is re-executable on backtracking.
Errors

`Head` is a variable |  | `instantiation_error`
`Head` is neither a variable nor a callable term |  | `type_error(callable, Head)`
The predicate indicator `Pred` of `Head` is that of a static procedure |  | `permission_error(modify, static_procedure, Pred)`

Portability
ISO predicate. In the ISO reference, the operation associated to the `permission_error` is `access` while it is `modify` in GNU Prolog. This seems to be an error of the ISO reference since for `asserta/1` (which is similar in spirit to `retract/1`) the operation is also `modify`.

7.7.4 | `retractall/1`

Templates

  `retractall(+head)`

Description
`retractall(Head)` erases all clauses whose head unifies with `Head`. The concerned predicate must be a dynamic procedure (section 7.7.1). The procedure definition is not removed so that it is found by `current_predicate/1` (section 7.8.1). `abolish/1` should be used to remove the procedure (section 7.7.6).
Errors

`Head` is a variable |  | `instantiation_error`
`Head` is not a callable term |  | `type_error(callable, Head)`
The predicate indicator `Pred` of `Head` is that of a static procedure |  | `permission_error(modify, static_procedure, Pred)`

Portability
GNU Prolog predicate.

7.7.5 | `clause/2`

Templates

  `clause(+head, ?callable_term)`

Description
`clause(Head, Body)` succeeds if there exists a clause in the database that unifies with `Head :- Body`. The predicate in question must be a public procedure (section 7.7.1). Clauses are delivered from the first to the last. This predicate is re-executable on backtracking.
Errors

`Head` is a variable |  | `instantiation_error`
`Head` is neither a variable nor a callable term |  | `type_error(callable, Head)`
The predicate indicator `Pred` of `Head` is that of a private procedure |  | `permission_error(access, private_procedure, Pred)`
`Body` is neither a variable nor a callable term |  | `type_error(callable, Body)`

Portability
ISO predicate.

7.7.6 | `abolish/1`

Templates

  `abolish(+predicate_indicator)`

Description
`abolish(Pred)` removes from the database the procedure whose predicate indicator is `Pred`. The concerned predicate must be a dynamic procedure (section 7.7.1).
Errors

`Pred` is a variable |  | `instantiation_error`
`Pred` is a term `Name/Arity` and either `Name` or `Arity` is a variable |  | `instantiation_error`
`Pred` is neither a variable nor a predicate indicator |  | `type_error(predicate_indicator, Pred)`
`Pred` is a term `Name/Arity` and `Arity` is neither a variable nor an integer |  | `type_error(integer, Arity)`
`Pred` is a term `Name/Arity` and `Name` is neither a variable nor an atom |  | `type_error(atom, Name)`
`Pred` is a term `Name/Arity` and `Arity` is an integer < 0 |  | `domain_error(not_less_than_zero, Arity)`
`Pred` is a term `Name/Arity` and `Arity` is an integer > `max_arity` flag (section 7.22.1) |  | `representation_error(max_arity)`
The predicate indicator `Pred` is that of a static procedure |  | `permission_error(modify, static_procedure, Pred)`

Portability
ISO predicate.

Copyright (C) 1999-2002 Daniel Diaz
Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.
More about the copyright