# Error with discontinuous predicate

**URL:** <https://swi-prolog.discourse.group/t/error-with-discontinuous-predicate/2961>\
**Category:** Help!\
**Created:** [September 23, 2020, 4:47pm UTC](https://swi-prolog.discourse.group/t/error-with-discontinuous-predicate/2961 "2020-09-23T16:47:00Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [September 23, 2020, 4:47pm UTC](https://swi-prolog.discourse.group/t/error-with-discontinuous-predicate/2961/1 "2020-09-23T16:47:00Z")

</div>

I’m writing a predicate to encode some typing information, but I want this to be `multifile` and `discontiguous`. So I have, in `typeDecls.pl`:

```prolog
:- module(typeDecls, [(::)/2]).

:- op(500, xfx, ::).
:- multifile((::)).
:- discontiguous((::)).

[] :: list(_).
[X|Xs] :: list(A) :- X :: A, Xs :: list(A).

%%% Some more stuff

```

Then I might have other files that define data structures, with the associated typing information; for example, in file `tree.pl`, I have:

```prolog
:- module(tree, [showTree/1]).
:- use_module(library(clpfd)).
:- use_module(typeDecls).

%%% NOTE this clause of the typing predicate
node(Node, Subforest) :: tree(NodeType) :-
    Node :: NodeType,
    Subforest :: list(tree(NodeType)).

showTree(T) :- showTree(T, 1).
showTree(node(Node, SubForest), Depth) :-
    once((
        writeLevel(Depth), write(' '), print(Node), write('\n'),
        DepthNext #= Depth+1,
        maplist({DepthNext}/[T]>>showTree(T, DepthNext), SubForest)
    )).

%%% Some more stuff

```

And wrapping this up, I might have in my main file something like:

```prolog
:- use_module(typeDecls).
:- use_module(tree).

%%% Some more stuff

```

When I consult the main file, I’m getting the error:

```prolog
ERROR: /home/.../tree.pl:5:22: Syntax error: Operator expected

```

and that position corresponds to my instance of the typing clause in `tree.pl`, as if that file couldn’t see the operator declaration in `typeDecls.pl`. Could you suggest how to fix this problem?

Thanks  
Carlo

---

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [September 23, 2020, 4:50pm UTC](https://swi-prolog.discourse.group/t/error-with-discontinuous-predicate/2961/2 "2020-09-23T16:50:46Z")

</div>

I just found the answer: [https://www.swi-prolog.org/pldoc/man?section=moduleop](https://www.swi-prolog.org/pldoc/man?section=moduleop)

basically operator declarations are local to modules, and if you want them to be visible from the import list, you should use something like:

```prolog
:- module(typeDecls, [op(500, xfx, ::), (::)/2]).

```

I’ll keep this thread open to ask questions related to this example, should they arise

---

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [September 23, 2020, 4:57pm UTC](https://swi-prolog.discourse.group/t/error-with-discontinuous-predicate/2961/3 "2020-09-23T16:57:42Z")

</div>

Here’s a subsequent question: now that I fixed the import as in the previous response, I get these warnings:

```prolog
Warning: /home/.../tree.pl:5:
Warning: Local definition of tree:(::)/2 overrides weak import from typeDecls

```

I don’t want that override to happen! That’s why I declared `(::)/2` as `multifile` in `typeDecls.pl`!  
On the other hand, I tried to write something like:

```prolog
:- module(typeDecls, [op(500, xfx, ::), multifile((::)), (::)/2]).

```

and that doesn’t work. So what’s the proper solution to signal that (::)/2 is multifile and thus should not be overrided?

I guess the core of this question is already contained in the comment at [https://www.swi-prolog.org/pldoc/man?predicate=multifile/1](https://www.swi-prolog.org/pldoc/man?predicate=multifile/1) from @CapelliC

---

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [September 24, 2020, 1:14am UTC](https://swi-prolog.discourse.group/t/error-with-discontinuous-predicate/2961/5 "2020-09-24T01:14:11Z")

</div>

Thanks @anon95304481, I’ll try this tomorrow when I’ll be back at the code. But in the meantime: why are we qualifying only the `::` functor in head? Should I also qualify the occurrences in the body, like

```prolog
    typeDecl:(Node :: NodeType)

```

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [September 24, 2020, 6:45am UTC](https://swi-prolog.discourse.group/t/error-with-discontinuous-predicate/2961/6 "2020-09-24T06:45:16Z")

</div>

> [@meditans](#):
>
> ```prolog
> :- multifile((::)).
> :- discontiguous((::)).
> 
> ```

This should be

```prolog
:- multifile((::)/2).
:- discontiguous((::)/2).

```

As is, it defines (::)/0. Actually it should raise an error. Will change that.

> [@meditans](#):
>
> But in the meantime: why are we qualifying only the `::` functor in head?

Both are valid, but mean something different. Qualifying the entire clause makes the clause behave the same as if it was defined in the indicated module. Qualifying the head adds a clause to the indicated module, but the body is executed in the context of the module where the clause appears. This is the most common way to deal with multifile predicates in modules.

---

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [September 24, 2020, 11:49am UTC](https://swi-prolog.discourse.group/t/error-with-discontinuous-predicate/2961/7 "2020-09-24T11:49:47Z")

</div>

Thanks for your answer, indeed the `tree.pl` file compiles without errors now.  
I have problems with my main file: I had this clause before:

```prolog
signature_decomposition({ A }, node(def, [])) :- A.

signature_decomposition(Term :: Type, node(Term :: Type, DecompositionList)) :-
    nonvar(Term),
    clause(Term :: Type, Constraints),
    conjunction_list(Constraints, ConstraintList),
    maplist(signature_decomposition, ConstraintList, DecompositionList).

signature_decomposition(Term :: Type, node(Term :: Type, [])) :-
    once(\+ clause(Term :: Type, _) ; var(Term)).

```

and was able to ask queries like:

```prolog
%?- signature_decomposition(member(A, [1,2,3]) :: T, D).

```

whereas now, that query just return false, because I have predicates of the form `user:(Term :: Type)` instead of just `Term :: Type`. I can change the head of the clause but at this point it’s quite arbitrary and I don’t understand which rule I should follow. I tried adding:

```prolog
:- meta_predicate signature_decomposition(:, -).

```

after reading the guide on metapredicates, but that didn’t help. I’d appreciate some guidance of how to get my code back to working.

Related question: can I write a term expansion so that every time `A ::: B` is read, it’s expanded in `typeDecls:(A :: B)`? Is this a common strategy for this problem?

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [September 24, 2020, 12:19pm UTC](https://swi-prolog.discourse.group/t/error-with-discontinuous-predicate/2961/8 "2020-09-24T12:19:33Z")

</div>

> [@meditans](#):
>
> `:- meta_predicate signature_decomposition(:, -).`

This is (probably) the right direction. Note that the predicate is then always called as `signature_decomposition(Module:Arg1, Arg2)`, so you have to write it to handle this construct properly. In this case I’d probably have a clause

```prolog
signature_decomposition(M:A, D) :-
    signature_decomposition(A, M, D).

```

Then the first clause becomes

```prolog
signature_decomposition({ A }, M, node(def, [])) :- call(M:A).

```

> [@meditans](#):
>
> Related question: can I write a term expansion so that every time `A ::: B` is read, it’s expanded in `typeDecls:(A :: B)` ? Is this a common strategy for this problem?

That is pretty common. It is probably as simple as

```prolog
term_expansion(A::B, typeDecls:(A::B)).
term_expansion((A::B :- Body), typeDecls:(A::B :- Body)).

```

If you define that in the file you write the rules you are fine. If you want to use this in many files I’d consider writing a file with all declarations that you can reuse using include/1.

---

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [September 24, 2020, 11:40pm UTC](https://swi-prolog.discourse.group/t/error-with-discontinuous-predicate/2961/9 "2020-09-24T23:40:48Z")

</div>

Thanks @jan, that’s getting me closer to the finish line!  
Now, I started wondering when prolog decides to return a term qualified with the module. Consider:

```prolog
typeDecls:(member(A,B) :: pred(T, list(T))) :-
    A :: T, B :: list(T).

```

and the interaction:

```prolog
?- clause(member(_, [1,2,3]) :: pred(A, list(A)), Clause).
Clause = user:(_6968::A, [1, 2, 3]::list(A)) .

```

why is that prefixed with the module `user`? I think that means `user:(,)(_6968::A, [1,2,3]::list(A))` (don’t know how to write the comma as prefix). And maybe it makes sense: the conjunction of that predicate lives indeed in `user`. But then, why not decorating the subterms also? Why isn’t the answer:

```prolog
Clause = user:(typeDecls(_6968::A), typeDecls:([1, 2, 3]::list(A))) .

```

I also discovered I can “solve” this problem with `strip_module`. So:

```prolog
?- clause(member(_, [1,2,3]) :: pred(A, list(A)), Clause), strip_module(Clause, _, Clause1).
Clause = user:(_246::A, [1, 2, 3]::list(A)),
Clause1 = (_246::A, [1, 2, 3]::list(A)) .

```

but I’d still like to understand where prolog decides to prefix with module informations.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [September 25, 2020, 7:22am UTC](https://swi-prolog.discourse.group/t/error-with-discontinuous-predicate/2961/10 "2020-09-25T07:22:35Z")

</div>

> [@meditans](#):
>
> why is that prefixed with the module `user` ?

Not entirely sure. I doubt clause/2 always does the correct thing. If however the above clause was declared in the context of `user` for the predicate that lives in `typeDecls`, qualifying the body using `user` makes sense. The assumption for the body of clause/2 is (I think) that the body lives in the same module as the predicate (head). If this is not the case, the body is qualified. So, this happens if a clause is added to a multifile predicate in another module **only** qualifying the head.

---

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [September 25, 2020, 11:16pm UTC](https://swi-prolog.discourse.group/t/error-with-discontinuous-predicate/2961/11 "2020-09-25T23:16:22Z")

</div>

> [@jan](#):
>
> If however the above clause was declared in the context of `user` for the predicate that lives in `typeDecls` , qualifying the body using `user` makes sense.

That’s exactly what was happening! In the end, with your hints, I was able to produce some code I’m happy with. Thanks a lot! In closing, which resources would you suggest to understand the nooks and crannies of swi’s module system, other than this tutorial [https://chiselapp.com/user/ttmrichter/repository/gng/doc/trunk/output/tutorials/swiplmodtut.html](https://chiselapp.com/user/ttmrichter/repository/gng/doc/trunk/output/tutorials/swiplmodtut.html) and the documentation on the swi website?

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [September 26, 2020, 7:23am UTC](https://swi-prolog.discourse.group/t/error-with-discontinuous-predicate/2961/12 "2020-09-26T07:23:17Z")

</div>

> [@meditans](#):
>
> which resources would you suggest to understand the nooks and crannies of swi’s module system

I fear the ones mentioned are as good as it gets ☹ Well, you can also learn from the libraries …

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [September 26, 2020, 11:08am UTC](https://swi-prolog.discourse.group/t/error-with-discontinuous-predicate/2961/13 "2020-09-26T11:08:41Z")

</div>

> [@meditans](#):
>
> I also discovered I can “solve” this problem with `strip_module` .

Are you aware that this site has a nice feature in that if you write the predicate indicator as text, it will be converted into a link to the documentation.

So instead of writing “strip\_module” if you write strip\_module/3 it will get converted to strip\_module/3. 🙂
