Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Module expansion of goals passed to library meta-predicates

Using SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.5), we proceed step by step:

  1. Define dcg nonterminal a//1 in module dcgAux (pronounced: "di-SEE-goh"):

    :- module(dcgAux,[a//1]).
    
    a(0)    --> [].
    a(s(N)) --> [a], a(N).
    
  2. Run the following queries—using phrase/2 and apply:foldl/4:

    ?- use_module([library(apply),dcgAux]).
    true.
    
    ?- phrase(      foldl(       a,[s(0),s(s(0))]),[a,a,a]).
    true.
    
    ?- phrase(      foldl(dcgAux:a,[s(0),s(s(0))]),[a,a,a]).
    true.
    
    ?- phrase(apply:foldl(dcgAux:a,[s(0),s(s(0))]),[a,a,a]).
    true.
    
    ?- phrase(apply:foldl(       a,[s(0),s(s(0))]),[a,a,a]).
    ERROR: apply:foldl_/4: Undefined procedure: apply:a/3
    

    нет! Quite a surprise—and not a good one. Have we been missing some unknown unknowns?

  3. To get rid of above irritating behavior, we must first find out the reason(s) causing it:

    ?- import_module(apply,M), M=user.
    false.
    
    ?- phrase(apply:foldl(a,[s(0),s(s(0))]),[a,a,a]).
    ERROR: apply:foldl_/4: Undefined procedure: apply:a/3
    
    ?- add_import_module(apply,user,end).
    true.
    
    ?- import_module(apply,M), M=user.   % sic!
    M = user.                            % `?- import_module(apply,user).` fails!
    
    ?- phrase(apply:foldl(a,[s(0),s(s(0))]),[a,a,a]).
    true.
    

What's going on? The way I see it is this:

  • Module expansion of the goal passed to foldl/4 is limited.
  • Quoting from the SWI-Prolog manual page on import_module/2:

    All normal modules only import from user, which imports from system.

  • SWI's library(apply) only "inherits" from system, but not user.

  • If we clone module apply to applY (and propagate the new module name), we observe:

    ?- use_module(applY).
    true.
    
    ?- phrase(applY:foldl(a,[s(0),s(s(0))]),[a,a,a]).  % was: ERROR
    true.                                              % now: OK!
    

Please share your ideas on how I could/should proceed!

(I have not yet run a similar experiment with other Prolog processors.)

like image 470
repeat Avatar asked Aug 21 '15 13:08

repeat


1 Answers

This is an inherent feature/bug of predicate based module systems in the Quintus tradition. That is, this module system was first developed for Quintus Prolog. It was adopted subsequently by SICStus (after 0.71), then (more or less) by 13211-2, then by YAP, and (with some modifications) by SWI.

The problem here is what exactly an explicit qualification means. As long as the goal is no meta-predicate, things are trivially resolvable: Take the module of the innermost qualification. However, once you have meta-predicates, the meta-arguments need to be informed of that module ; or not. If the meta-arguments are informed, we say that the colon sets the calling context, if not, then some other means is needed for that purpose.

In Quintus tradition, the meta-arguments are taken into account. With the result you see. As a consequence you cannot compare two implementations of the same meta-predicate in the same module directly. There are other approaches most notably IF and ECLiPSe that do not change the calling context via the colon. This has advantages and disadvantages. The best is to compare them case by case.

Here is a recent case. Take lambdas and how they are put into a module in SICStus, in SWI, and in ECLiPSe.

As for the Quintus/SICStus/YAP/SWI module system, I'd rather use it in the most conservative manner possible. That is:

  • no explicit qualification, consider the infix : as something internal

  • clean, checkable meta-declarations - insert on purpose an undefined predicate just to see whether or not cross-referencing is able to detect the problem (in SWI that's check or make).

  • use the common subset, avoid the many bells and whistles - there are many well meant extensions...

  • do more versatile things the pedestrian way: reexport by adding an appropriate module and add a dummy definition. Similarly, instead of renaming, import things from an interface module.

  • be always aware that module systems have inherently some limits. No matter how you twist or turn it. There is no completely seamless module system, for the very purpose of modules is to separate code and concerns.


1: To be precise, SICStus' adaptation of Quintus modules did only include : for module sensitive arguments in meta_predicate declarations. The integers 0..9, which are so important for higher-order programming based on call/N were only introduced about 20 years later in 4.2.0 released 2011-03-08.

like image 192
false Avatar answered Sep 29 '22 01:09

false