/* $Id$ Part of BOOT Designed and implemented by Jan Wielemaker E-mail: jan@swi.psy.uva.nl Copyright (C) 1998 University of Amsterdam. All rights reserved. */ :- module(blackboard, [ set_blackboard/2, % -Old, +New current_blackboard/1, % ?Identifier bdefault/1, % +Module (or BlackBoard) block/1, % +Head bunlock/1, % +Head bunlock/2, % +Head, +BroadCast blocked/1, % +Head bassert/1, % +Term basserta/1, % +Term bretract/1, % +Term bretractall/1, % +Term bset/2, % +Head, +Value bterm/1, % ?Term bonce/1, % ?Term bsave/1, % +File bload/1 % +File ]). :- use_module(library(broadcast)). :- use_module(library(pretty_print)). /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - library(library(blackboard)) Generic (simple) blackboard library based on the broadcast library for forwarding changes to interested clients of the blackboard. The package is based on the notion of a `current' blackboard. The manipulation predicate all start with a `b', and otherwise have the conventional Prolog names and semantics. Modifications raise the following broadcast messages: bmodified(Head, Modification) Where Modification is one of: added(Term, ) removed(Term). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ :- dynamic current_blackboard/1, lock/2. current_blackboard(default_bb). :- initialization default_bb:unknown(_, fail). current_blackboard_(BB) :- current_blackboard(CBB), !, BB = CBB. current_blackboard_(_) :- throw(bberror(no_backboard)). % set_blackboard(-Old, +New) % % Set the current blackboard. Unify `Old' with the old bb, or [] if % there is no current bb. set_blackboard(Old, New) :- Old == New, !, current_blackboard_(Old). set_blackboard(Old, New) :- current_blackboard_(Old), nonvar(New), retractall(current_blackboard(New)), asserta(current_blackboard(New)). % bdefault +Module % % Assign a Prolog module as a default. Note the default can also % be another blackboard! bdefault(Module) :- blterm('$bb_default_to'(Module)), !. bdefault(Module) :- bassert('$bb_default_to'(Module)). % bassert(+Term) % basserta(+Term) % % Add a term to the blackboard. bassert(Term) :- current_blackboard_(BB), assert(BB:Term), broadcast(bmodified(Term, added(end))). basserta(Term) :- current_blackboard_(BB), asserta(BB:Term), broadcast(bmodified(Term, added(start))). % bset(+Head, +Value) % % Assume a blackboard term consisting of `Head' with `Value' appended. % Remove all terms where `Value' is a variable, then assert the new % relation. bset(Head, Value) :- current_blackboard_(BB), Head =.. List0, append(List0, [VarValue], List1), Term =.. List1, retractall(BB:Term), Value = VarValue, assert(BB:Term), broadcast(bmodified(Term, set)). % bretract(+Term) % bretractall(+Term) % bretract(Term) :- current_blackboard_(BB), retract(BB:Term), broadcast(bmodified(Term, removed)). bretractall(Term) :- current_blackboard_(BB), ( retract(BB:Term), broadcast(bmodified(Term, removed)), fail ; true ). % b(un)lock(+Term) % % Lock group of changes to a relation. Will broadcast % bmodified(Term) after the final unlock. block(Term) :- functor(Term, Name, Arity), functor(Head, Name, Arity), current_blackboard_(BB), asserta(lock(Head, BB)). bunlock(Term) :- bunlock(Term, true). bunlock(Term, Broadcast) :- functor(Term, Name, Arity), functor(Head, Name, Arity), current_blackboard_(BB), retract(lock(Head, BB)), !, ( ( lock(Term, BB) ; Broadcast == false ) -> true ; broadcast(bmodified(Head)) ). blocked(Term) :- functor(Term, Name, Arity), functor(Head, Name, Arity), current_blackboard_(BB), lock(Head, BB), !. clear_blackboard :- current_blackboard_(BB), ( current_predicate(_, BB:Head), retract(BB:Head), fail ; broadcast(bcleared(BB)) ). % bterm(-Term) % /* bterm(Term) :- ( current_blackboard(BB) -> current_predicate(_, BB:Term), BB:Term ). bterm(Term) :- blterm('$bb_default_to'(M)), current_predicate(_, M:Term), M:Term. */ bterm(Term) :- ( current_blackboard(BB) -> BB:Term ). bterm(Term) :- current_blackboard(BB), !, catch(BB:'$bb_default_to'(M), _, fail), catch(M:Term, error(existence_error(procedure, _), _), fail). % bonce(-Term) % % As bterm/1, but deterministic bonce(Term) :- bterm(Term), !. % blterm(-Term) % % Local version of bterm blterm(Term) :- current_blackboard_(BB), current_predicate(_, BB:Term), BB:Term. % bsave(+File) % % Save blackboard contents to file bsave(File) :- open(File, write, Fd), current_blackboard_(BB), get_time(Time), bset(saved_at, Time), format(Fd, '/* Generated file: Saved blackboard.~n', []), format(Fd, '*/~n~n', []), format(Fd, 'blackboard(~q).~n~n', [BB]), ( blterm(Term), numbervars(Term, 0, _), % write_term(Fd, Term, [quoted(true), numbervars(true)]), pretty_print(Fd, Term), fail ; close(Fd) ). % bload(+File) % % Load blackboard contents from file bload(File) :- open(File, read, Fd), ( read(Fd, blackboard(BB)) -> set_blackboard(_, BB), clear_blackboard, read(Fd, Term), retractall(current_relation(_)), bload(Term, Fd) ; close(Fd), throw(berror(not_a_blackboard_file(File))) ), close(Fd). :- dynamic current_relation/1. make_current(Term) :- functor(Term, Name, Arity), functor(Head, Name, Arity), ( current_relation(Head) -> true ; forall(retract(current_relation(Old)), bunlock(Old)), asserta(current_relation(Head)), block(Term) ). bload(end_of_file, _) :- !, make_current([]). bload(Term, Fd) :- make_current(Term), bassert(Term), repeat, read(Fd, Term2), !, bload(Term2, Fd).