retract/1とabolish/2の違い

SWI-Prologにはグローバルメモリ上からデータを削除する組み込み述語が二つある。一つが、retract/1で、もう一つがabolish/2。

例えば、まず以下のようにグローバルメモリにデータを書き込んだとき

?- assert(hoge).
true.
?- listing(hoge).
:- dynamic hoge/0.
hoge
true

この「hoge」は以下どちらでも消すことができる。

?- retract(hoge).
true.

又は

?- abolish(hoge,0).
true

問題は、これら二つの削除述語、同じ役割かと思っていたけれどどうやら違うみたい。retract/1は「書き込まれたメモリを初期化する」役割で、abolish/2は「書き込まれたメモリをヒープから外す」という感じ。

例えば、retract/1を使った場合

?- retract(hoge).
true.
?- listing(hoge).
:- dynamic hoge/0.
true.

と動的に割り当てられたメモリ空間は残ったまま。しかしabolish/2だと。

?- abolish(hoge,0).
true
?- listing(hoge).
% Execution Aborted
true.

と「名前がない」とエラーを吐く。さらにこのことは困った違いを生み、モジュール内の述語をretract/1で消してもモジュール名は残ったままになるが、abolish/2では、モジュール内の述語をabolish/2で消すと、モジュールそのものが消える。

おそらくretract/1の方がmallocを呼び出さないため、何度も書き換えを行う場合は有利、だがモジュールを汚染区域のように使い捨てる場合は、abolish/2の方が安全。