Re: handling state the database way

Paulo Moura <[email protected]>
Newsgroups gmane.comp.ai.prolog.swi
Message-ID <[email protected]>
On 18/02/2014, at 10:05, Jan Wielemaker <[email protected]> wrote:

> On 02/18/2014 10:36 AM, Paulo Moura wrote:
>> The design idea behind the "single_fact" module centralizes (for an
>> application) the handling of mutable data.  This can be both an
>> advantage (a single place to hold the mutable data) and a
>> disadvantage (multiple modules using this module must be careful to
>> use different keys). This makes "single_fact" more like a *prototype*
>> solution than an ideal *library* solution. As a library solution it
>> comes with a bias towards a single central, global store.
>> 
>> Logtalk provides a bit more flexible library solution by using a
>> category instead. A Logtalk category is a fine-grined unit of code
>> reuse that can be (virtually) imported by any object. Using the
>> "single_fact" module suggested predicates, we can define:
> 
> Logtalk's abstracting has a cleaner design than classical Prolog
> modules,

Thanks :-)

> but that doesn't mean we can't realise module local
> storage with Prolog modules:

Sure it's possible. That's one of the reasons I referred to the original "single_fact" module as a prototype solution.

> :- meta_predicate
> 	initialize(:, +),
> 	...
> 
> initialize(Module:Key, Value) :-
> 	asserta(Module:store(Key, Value)).
> 
> ...
> 
> And the central store is just
> 
> 	initialize(central:size, 42).

So we moved from a first "single_fact" module prototype to a second, arguably more flexible one:

:- module(single_fact, [
	initialise/2,
	access/2,
	update/2,
	finalise/1
]).
:- meta_predicate
	initialise(:, +),
	access(:, +),
	update(:, 2),
	finalise(:).

:- dynamic store/2.

initialise(Module:Key, Datum) :-
   retractall(Module:store(Key,_)),
   assert(Module:store(Key, Datum)).

access(Module:Key, Datum) :-
	Module:store(Key, Datum).

update(Module:Key, Updater) :-
   retract(Module:store(Key, Old)),
   !, /* green cut */
   (   call(Updater, Old, New) -> F = true
   ;   New = Old, F = fail
   ),
   assert(Module:store(Key, New)),
   F == true.

finalise(Module:Key) :-
   retractall(Module:store(Key,_)).

The caveats with this solution: (1) the keys *may* need to be explicitly qualified, depending on the usage scenario; (2) looking into code of the modules using the "single_fact" module it's not apparent that each using module now also have a store/2 dynamic predicate.

(1) may be a nuisance when handing keys or simply a no-problem.

(2) it's interesting by its own from a tools perspective. In the case of the Logtalk solution, the declaration of the private and dynamic store/2 predicate is inherited by the objects importing the category. In the case of the module solution, *after* the store being initialized, the query current_predicate(central:sore/2) succeeds.

Cheers,

Paulo

-----------------------------------------------------------------
Paulo Moura
Logtalk developer

Email: <mailto:[email protected]>
Web:   <http://logtalk.org/>
-----------------------------------------------------------------
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.