A cross-module "interface" call in SWI-Prolog - module

This may be specific to the SWI Prolog module system.
Suppose we have three Prolog modules (in the SWI-Prolog module system):
robin (in file robin.pl)
arthur (in file arthur.pl)
helper (in file helper.pl).
Predicates robin:robin/0 (i.e. predicate robin_hood/0 in module robin) and predicate arthur:arthur/0 call predicate helper:helper/2 (which is exported by module helper).
Predicate helper:helper/2 then should call a predicate toolshed/1, which is different depending on the caller modules. I would like helper/2 to call the toolshed/1 predicate associated with the predicate that calls helper/2.
In Java, one would pass an interface with a toolshed() method to helper(), so that helper() can call the interface and end up at the correct implementation.
How do I do it in Prolog?
Example code:
robin.pl
:- module(robin,
[
robin/0
,toolshed/1
]).
:- use_module(library('helper.pl')).
robin :- helper(friar_tuck,help).
toolshed('a katana made by mastersmith Masamune').
toolshed('an ancient shovel with a sharpened blade').
toolshed('an Uzi 9mm with Norinco markings').
arthur.pl
:- module(arthur,
[
arthur/0
,toolshed/1
]).
:- use_module(library('helper.pl')).
arthur :- helper(merlin,help).
toolshed('a slightly musty grimoire').
toolshed('a jar of mandragore').
toolshed('a fresh toadstool').
helper.pl
:- module(helper,
[
helper/2
]).
helper(friar_tuck,help) :-
format("I will help you rout the Sheriff of Nottingham's men!~n"),
setof(X,toolshed(X),Tools),
format("I found these tools: ~q~n",[Tools]),
format("Have at them!~n").
helper(merlin,help) :-
format("I will help you rout Mordred's army!~n"),
setof(X,toolshed(X),Tools),
format("I found these tools: ~q~n",[Tools]),
format("Have at them!~n").
Put them into a director testing:
testing
├── arthur.pl
├── helper.pl
└── robin.pl
Launch swipl, set the library search path and load arthur.pl:
?- assertz(file_search_path(library,'/home/me/testing')).
true.
?- use_module(library('arthur.pl')).
true.
?- arthur.
I will help you rout Mordred's army!
I found these tools: ['a fresh toadstool','a jar of mandragore','a slightly musty grimoire']
Have at them!
true.
So this works. toolshed/1 is exported by module arthur and visible (and callable unqalified) by module helper even though helper does not import arthur.pl (not quite sure how that works, mabye the exported predicates of all modules belonging to predicates currently on the stack are visible and accessible unqalified?).
But I can't load robin.pl too:
?- use_module(library('robin.pl')).
ERROR: import/1: No permission to import robin:toolshed/1 into user (already imported from arthur)
true.
Ok, this is not surprising. But how do I get the result I want? I want to see this:
?- use_module(library('robin.pl')).
true.
?- robin.
I will help you rout the Sheriff of Nottingham's men!
I found these tools: ['a katana made by mastersmith Masamune','an Uzi 9mm with Norinco markings','an ancient shovel with a sharpened blade']
Have at them!
true.

Using the SWI-Prolog proprietary module-transparent mechanism do provide a working alternative. But be aware that this mechanism is not only marked as "Direct usage by programmers is deprecated." but also have other problems not mentioned in that documentation.
In this solution, we make the helper/2 predicate module transparent:
:- module(helper, [helper/2]).
:- module_transparent(helper/2).
helper(friar_tuck,help) :-
format("I will help you rout the Sheriff of Nottingham's men!~n"),
setof(X,toolshed(X),Tools),
format("I found these tools: ~q~n",[Tools]),
format("Have at them!~n").
helper(merlin,help) :-
format("I will help you rout Mordred's army!~n"),
setof(X,toolshed(X),Tools),
format("I found these tools: ~q~n",[Tools]),
format("Have at them!~n").
The other modules are then simplified to:
:- module(arthur, [arthur/0]).
:- use_module('helper.pl').
arthur :- helper(merlin,help).
toolshed('a slightly musty grimoire').
toolshed('a jar of mandragore').
toolshed('a fresh toadstool').
and:
:- module(robin, [robin/0]).
:- use_module('helper.pl').
robin :- helper(friar_tuck,help).
toolshed('a katana made by mastersmith Masamune').
toolshed('an ancient shovel with a sharpened blade').
toolshed('an Uzi 9mm with Norinco markings').
We then get:
?- [helper, arthur, robin].
true.
?- arthur.
I will help you rout Mordred's army!
I found these tools: ['a fresh toadstool','a jar of mandragore','a slightly musty grimoire']
Have at them!
true.
?- robin.
I will help you rout the Sheriff of Nottingham's men!
I found these tools: ['a katana made by mastersmith Masamune','an Uzi 9mm with Norinco markings','an ancient shovel with a sharpened blade']
Have at them!
true.
That said, this and the other modules solutions have several issues and don't scale well to more complex cases as the features that you're looking for (notably, interfaces/protocols as a first class construct) don't exist in Prolog modules systems and hacks fall short (see e.g. https://logtalk.org/blog.html?tag=half+broken+hacks).

You can make your code work with multifile predicates as well. [Update: this solves the loading conflict but without more changes both robin and arthur can use each other tools.] But the primary multifile predicate declaration (i.e. the one without an explicit module qualification) must be on the helper module:
:- module(helper, [helper/2]).
:- multifile(toolshed/1).
helper(friar_tuck,help) :-
format("I will help you rout the Sheriff of Nottingham's men!~n"),
setof(X,toolshed(X),Tools),
format("I found these tools: ~q~n",[Tools]),
format("Have at them!~n").
helper(merlin,help) :-
format("I will help you rout Mordred's army!~n"),
setof(X,toolshed(X),Tools),
format("I found these tools: ~q~n",[Tools]),
format("Have at them!~n").
The arthur module becomes:
:- module(arthur, [arthur/0]).
:- use_module('helper.pl').
arthur :- helper(merlin,help).
:- multifile(helper:toolshed/1).
helper:toolshed('a slightly musty grimoire').
helper:toolshed('a jar of mandragore').
helper:toolshed('a fresh toadstool').
Similar for the robin module:
:- module(robin, [robin/0]).
:- use_module('helper.pl').
robin :- helper(friar_tuck,help).
:- multifile(helper:toolshed/1).
helper:toolshed('a katana made by mastersmith Masamune').
helper:toolshed('an ancient shovel with a sharpened blade').
helper:toolshed('an Uzi 9mm with Norinco markings').
Sample calls:
?- [helper, arthur, robin].
true.
?- arthur.
I will help you rout Mordred's army!
I found these tools: ['a fresh toadstool','a jar of mandragore','a katana made by mastersmith Masamune','a slightly musty grimoire','an Uzi 9mm with Norinco markings','an ancient shovel with a sharpened blade']
Have at them!
true.
?- robin.
I will help you rout the Sheriff of Nottingham's men!
I found these tools: ['a fresh toadstool','a jar of mandragore','a katana made by mastersmith Masamune','a slightly musty grimoire','an Uzi 9mm with Norinco markings','an ancient shovel with a sharpened blade']
Have at them!
true.
Btw, never write:
:- use_module(library('helper.pl')).
when you're loading another module that's in the same directory as the importing module. That's just begging for trouble as library is a directory alias with potentially multiple definitions (in an order that most likely you're not controlling) coupled with a search mechanism.

An interesting problem. Follows a fully portable Logtalk solution (with minor changes for portability and avoiding dependencies on the pesky double_quotes flag; format/2 is a de facto standard predicate that accepts an atom in the first argument but the way the predicate is made available depends on the Prolog system and there's no need of cluttering the code with those details):
:- protocol(toolshed).
:- public(toolshed/1).
:- end_protocol.
:- category(helper).
:- private(helper/2).
helper(friar_tuck, help) :-
write('I will help you rout the Sheriff of Nottingham\'s men!\n'),
setof(X, ::toolshed(X), Tools),
write('I found these tools: '), writeq(Tools), nl,
write('Have at them!\n').
helper(merlin, help) :-
write('I will help you rout Mordred\'s army!\n'),
setof(X, ::toolshed(X), Tools),
write('I found these tools: '), writeq(Tools), nl,
write('Have at them!\n').
:- end_category.
:- object(robin,
implements(toolshed),
imports(helper)).
:- public(robin_hood/0).
robin_hood :-
^^helper(friar_tuck, help).
toolshed('a katana made by mastersmith Masamune').
toolshed('an ancient shovel with a sharpened blade').
toolshed('an Uzi 9mm with Norinco markings').
:- end_object.
:- object(arthur,
implements(toolshed),
imports(helper)).
:- public(arthur/0).
arthur :-
^^helper(merlin, help).
toolshed('a slightly musty grimoire').
toolshed('a jar of mandragore').
toolshed('a fresh toadstool').
:- end_object.
Then (assuming the above code saved in a dh.lgt file):
$ swilgt
...
?- {dh}.
...
true.
?- robin::robin_hood.
I will help you rout the Sheriff of Nottingham's men!
I found these tools: ['a katana made by mastersmith Masamune','an Uzi 9mm with Norinco markings','an ancient shovel with a sharpened blade']
Have at them!~n
true.
?- arthur::arthur.
I will help you rout Mordred's army!
I found these tools: ['a fresh toadstool','a jar of mandragore','a slightly musty grimoire']
Have at them!~n
true.
You can run this solution not only with Logtalk but with all its supported backend Prolog systems.
If you don't want the toolshed/1 predicate to be public, you can change the object opening directives to make the predicate either protected or private. For example:
:- object(robin,
implements(private::toolshed),
imports(helper)).
This will give you:
?- arthur::toolshed(T).
! Permission error: access private_predicate toolshed/1
! in goal: arthur::toolshed(A)
You could also change the protocol to make the predicate private there but that would not be idiomatic.

Looks like I stumbled upon a solution:
The new helper.pl
It has a modified helper/2: now helper/3 which accepts the module name of the caller as third argument and uses it to qualify the call to toolshed/1:
(is it possible to find out by which module one is currently being called? without creating a stack trace?)
:- module(helper,
[
helper/3
]).
helper(friar_tuck,help,Module) :-
format("I will help you rout the Sheriff of Nottingham's men!~n"),
setof(X,Module:toolshed(X),Tools),
format("I found these tools: ~q~n",[Tools]),
format("Have at them!~n").
helper(merlin,help,Module) :-
format("I will help you rout Mordred's army!~n"),
setof(X,Module:toolshed(X),Tools),
format("I found these tools: ~q~n",[Tools]),
format("Have at them!~n").
The new arthur.pl
Does not export toolshed/1 and passes the name of the arthurmodule in the call tohelper:helper/3`. (Is it possible to find the name of the current module? This hardcoding is an accident waiting to happen).
:- module(arthur,
[
arthur/0
]).
:- use_module(library('helper.pl')).
arthur :- helper(merlin,help,arthur). % Give module name as third argument
toolshed('a slightly musty grimoire').
toolshed('a jar of mandragore').
toolshed('a fresh toadstool').
The new robin.pl
:- module(robin,
[
robin/0
]).
:- use_module(library('helper.pl')).
robin :- helper(friar_tuck,help,robin). % Give module name as third argument
toolshed('a katana made by mastersmith Masamune').
toolshed('an ancient shovel with a sharpened blade').
toolshed('an Uzi 9mm with Norinco markings').
And it indeed works. Both modules arthur and robin can be loaded at the same time because toolshed/1 is no longer exported, but can still be used from helper:helper/3.
Start swipl, then:
?- assertz(file_search_path(library,'/home/me/testing')).
true.
Now I can load both modules, as there is no clash on the unexported toolshed/1:
?- use_module(library('robin.pl')).
true.
?- use_module(library('arthur.pl')).
true.
And calling toolshed/1 in qualified fashion works well:
?- robin.
I will help you rout the Sheriff of Nottingham's men!
I found these tools: ['a katana made by mastersmith Masamune','an Uzi 9mm with Norinco markings','an ancient shovel with a sharpened blade']
Have at them!
true.
?- arthur.
I will help you rout Mordred's army!
I found these tools: ['a fresh toadstool','a jar of mandragore','a slightly musty grimoire']
Have at them!
true.
This seems right enough, although I still don't know why the non-exported toolshed/1 can actually be called.

Related

How to remove a package from defpackage?

I defined a package like this:
(defpackage :web-app
(:nicknames :wa)
(:use :cl :hunchentoot))
This works fine.
But I want to remove hunchentoot. When I remove it and recompile I get the following error:
Unknown location:
warning:
WEB-APP also uses the following packages:
(HUNCHENTOOT)
See also:
Common Lisp Hyperspec, DEFPACKAGE [:macro]
SBCL Manual, *ON-PACKAGE-VARIANCE* [:variable]
How do I remove packages from my lisp image in these cases.
I have tried restarting the image but no luck.
In this case the function to use is unuse-package. For example:
(unuse-package :hunchentoot :web-app)
That will sync the package system with your defpackage form so it will re-evaluate without a warning.

How do I find the version and authority of a Perl 6 module?

In Bar.pm, I declare a class with an authority (author) and a version:
class Bar:auth<Camelia>:ver<4.8.12> {
}
If I use it in a program, how do I see which version of a module I'm using, who wrote it, and how the module loader found it? As always, links to documentation are important.
This question was also asked on perl6-users but died before a satisfactory answer (or links to docs) appeared.
Another wrinkle in this problem is that many people aren't adding that information to their class or module definitions. It shows up in the META.json file but not the code.
(Probably not a satisfying answer, because the facts of the matter are not very satisfying, especially regarding the state of the documentation, but here it goes...)
If the module or class was versioned directly in the source code à la class Bar:auth<Camelia>:ver<4.8.12>, then any code that imports it can introspect it:
use Bar;
say Bar.^ver; # v4.8.12
say Bar.^auth; # Camelia
# ...which is short for:
say Bar.HOW.ver(Bar); # v4.8.12
say Bar.HOW.auth(Bar); # Camelia
The ver and auth methods are provided by:
Metamodel::ClassHOW (although that documentation page doesn't mention them yet)
Metamodel::ModuleHOW (although that documentation page doesn't exist at all yet)
Unfortunately, I don't think the meta-object currently provides a way to get at the source path of the module/class.
By manually going through the steps that use and require take to load compilation units, you can at least get at the prefix path (i.e. which location from $PERL6LIB or use lib or -I etc. it was loaded from):
my $comp-spec = CompUnit::DependencySpecification.new: short-name => 'Bar';
my $comp-unit = $*REPO.resolve: $comp-spec;
my $comp-repo = $comp-unit.repo;
say $comp-repo.path-spec; # file#/home/smls/dev/lib
say $comp-repo.prefix; # "/home/smls/dev/lib".IO
$comp-unit is an object of type CompUnit.
$comp-repo is a CompUnit::Repository::FileSystem.
Both documentations pages don't exist yet, and $*REPO is only briefly mentioned in the list of dynamic variables.
If the module is part of a properly set-up distribution, you can get at the meta-info defined in its META6.json (as posted by Lloyd Fournier in the mailing list thread you mentioned):
if try $comp-unit.distribution.meta -> %dist-meta {
say %dist-meta<ver>;
say %dist-meta<auth>;
say %dist-meta<license>;
}

MS SQL Config With Slick 2.0.1 And Playframework 2.2.2

When I try to use the new proprietary MS SQL driver, I get an exception which boils down to a ClassNotFound for the driver class.
I include both slick and slick-extensions:
"com.typesafe.slick" %% "slick" % "2.0.1",
"com.typesafe.slick" %% "slick-extensions" % "2.0.1"
Example use:
import com.typesafe.slick.driver.ms.SQLServerDriver.simple._
Database.forURL(url="jdbc:sqlserver://hostname:1433;databaseName=thedb1", driver = "com.typesafe.slick.driver.ms.SQLServerDriver", user="user", password="password" ) withSession { ...
Exception:
Ultimately, ClassNotFound for com.typesafe.slick.driver.ms.SQLServerDriver.
I ran across the same issue and was able to solve it by defining the following lines in the application.conf file (thanks to the help from the play-slick contributors here):
db.default.slickdriver=com.typesafe.slick.driver.ms.SQLServerDriver
db.default.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
Alternatively, you could use the jTDS driver from sourceforge like listed in the question's comments.
db.default.slickdriver=com.typesafe.slick.driver.ms.SQLServerDriver
db.default.driver=net.sourceforge.jtds.jdbc.Driver
I ended up doing the first option, which meant downloading the unmanaged dependency sqljdbc4.jar(available here) and placing it on the {play app root}/lib directory.
Since the jTDS driver is available as a library dependency for build.sbt, I'd suggest trying that one first.

extra-paths not added to python path with zc.recipe.testrunner

I am trying to run tests by adding a version of tornado downloaded from github.com in the sys.path.
[tests]
recipe = zc.recipe.testrunner
extra-paths = ${buildout:directory}/parts/tornado/
defaults = ['--auto-color', '--auto-progress', '-v']
But when I run bin/tests I get the following error :
ImportError: No module named tornado
Am I not understanding how to use extra-paths ?
Martin
Have you tried looking into generated bin/tests script if it contains your path? It will tell definitely if your buildout.cfg is correct or not. Maybe problem is elsewhere. Because it seem that your code is ok.
If you happen to regularly include various branches from git/mercurial or elsewhere to buildout, you might be interested in mr.developer. mr.developer can download and add package to develop =. You wont need to set extra-path in every section.

Branching with clearcase remote client

I am trying to branch a file in ClearCase Remote Client.
I have the branch set up and the config spec is updated to handle the branch.
But I can't find the option, and the googling isn't helping much.
The way I understand your question, it sounds like you want to somehow select a command from a Clearcase RC menu(s) and have the branch explicitly created(?)
Clearcase has no explicit "Generate Branch for this File" command; you would want the "Checkout" command in this case. Branching is indirect and is a result of checking out a version of a file in a view that has a config spec with the '-mkbranch ' operation in it. I.e. the following config spec will create the dev_1.0_branch once I check it out (for any and all vobs and files):
element * CHECKEDOUT
element * .../dev_1.0_branch/LATEST
element * /main/LATEST -mkbranch dev_1.0_branch
The first line is standard for views in which you are doing development, line 2 will assure that I see any file that has a dev_1.0_branch (particularly important for the checkout+mkbranch to work as expected :-), and line 3 will select the latest version of any file that does not have a dev_1.0_branch and will create the branch if (and only if) the file version selected by that rule is checked out.
Please let me know if any of the above sounds greek to you, particularly any of the config spec rules. Having worked with ClearCase for a long time, I assume and use a lot of its terminology and concepts as if it's common knowledge :-P.
One thing of note: if you checkout the file, then immediately uncheckout the file, you will leave an empty branch on that file (i.e. in the above you would have a file with a version such as: foo.c##/main/dev_1.0_branch/0, but no /main/dev_1.0_branch/1 version). Many sites prefer to keep the version tree clean and remove empty branches (one can be found in this IBM Rational Technical article)
Just to be clear, I'm familiar with ClearCase Base & ClearCase MultiSite, but have not worked with the Remote Client yet.
--- 2009-Jun-29 Update
In response to Paul's comment below, if you want to be selective in what files are branched, you can modify the "*" to be more specific. For example, if you want to only branch foo.c in the FOODEV VOB, but leave everything else on main:
UNIX config spec:
element * CHECKOUT
element * .../my_dev_branch/LATEST
element /vobs/FOODEV/src/foo.c -mkbranch my_dev_branch
element * /main/LATEST
(For windows, you would want to use Windows conventions. I.e. \FOODEV\src\foo.c).
You can also select a directory and all elements below the directory (again UNIX config spec):
element * CHECKOUT
element * .../my_dev_branch/LATEST
element /vobs/FOODEV/src/mycomponent/... -mkbranch my_dev_branch
element * /main/LATEST
The main page for config_spec (cleartool man config_spec from the command line on windows or unix) provides decent guidance in the "Pattern" section for how to write the element/version selector (2nd column).
You can do a lot of complex version selection with the config specs. Please let me know if you would like more details or specifics.
Here's a config spec that I used for fixing a particular bug, with names changed to disguise some of the guilty.
element * CHECKEDOUT
element * .../TEMP.bugnum171238.jleffler/LATEST
mkbranch -override TEMP.bugnum171238.jleffler
include /clearcase/cspecs/project/version-1.23.45
To create the branch, in each VOB, I used a command:
ct mkbrtype -c 'Branch for bug 171238' TEMP.bugnum171238.jleffler#/vobs/project
Previously, we used config specs with -mkbranch rules appended to the various element lines.