Did you know ... | Search Documentation: |
Pack memo -- README |
This package provides library(memo)
, a tool for memoising deterministic
predicates in memory or persistently on the file system.
It also includes library(typedef)
, which provides support for defining
algebraic data types that hook into the type-checking framework of
library(error).
See library(memo)
module header for more information.
This is a small test file that you can use to check if it works.
:- use_module(library(memo)). :- use_module(library(typedef)). :- type maybe(A) ---> nothing; just(A). :- volatile_memo sqrt1(+float, -maybe(float)). :- persistent_memo sqrt2( +float, -float). sqrt1(X,just(Y)) :- X>=0, !, Y is sqrt(X). sqrt1(_,nothing). % this will throw an exception if X<0 sqrt2(X,Y) :- Y is sqrt(X). :- initialization db_attach('test.db',[]), % attach database for persistent memo debug(memo). % tocheck memoisation operations
Then, you can make queries such as
?- sqrt1(16,X). % leads to type error (16 is not a float) ?- sqrt1(16.0,X). % computes X=4.0 ?- sqrt1(16.0,X). % looks up old result, X=4.0 ?- sqrt1(-4.0,X). % fails ?- sqrt2(9.0,X). % computes X=3.0 and stores persistently ?- sqrt2(-4.0,X). % records exception and then rethrow is ?- sqrt2(-4.0,X). % rethrows recorded exception
The debug messages should indicate that repeated computations are being
avoided, even for failing goals, like sqrt1(-4.0,X)
, and computations
that throw exceptions, like sqrt2(-4.0,X)
.
memo/1 and memo/2 are now steadfast with respect to output arguments in the memoised goal. This means that instead of throwing an exception if an output argument is nonvar on entry, the computation proceeeds _exactly_ as if it were unbound, followed by a final semi-deterministic unification. Any side-effects of calling the memoised computation (ie the memoisation of the result) goes ahead even if the output arguments do not unify and the call as a whole fails. An alternative approach would be to abort the memoisation if the output values do not unify with those provided on input.
memo/1 now behaves differently if the memoised predicate fails or throws an exception, in which case the result will now NOT be stored. This is probably the more useful behaviour on the whole, because failures and exceptions are more likely to be due to bugs rather than any inherent partiality in the function being computed.
The library now has a notion of 'current evaluation mode', which applies when memoised predicates are called directly by their original names. In the previous version, this resulted in a call to memo/1, i.e., strict mode checking is done, previously stored computations are checked, and a new computation done if necessary and the result stored. In v0.3, the current mode can be 'memo', 'browse' or 'compute', which result in calls to memo/1, browse/1 or compute/1 respectively. The initial mode is 'memo', retaining backwards compatibility with v0.2. The only way to affect the mode is to use call_with_mode(Mode,Goal), which calls an arbitrary goal in an environment with the evaluation mode set to Mode. There is no way to globally set the evaluation-mode -- this is an intentional design decision to ensure that any goal given at the top level ?- prompt always behaves the same way.