Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Is succ/2 correctly implemented in SWI-Prolog? What about length/2?

285 views
Skip to first unread message

burs...@gmail.com

unread,
Jul 6, 2018, 12:42:10 PM7/6/18
to
I have recently added succ/2 to my module arith.
On purpose I have implemented it *wrongly*. But
maybe its not that wrongly how implemented it.

I read:

succ(P, S) <-> integer(P) & integer(S) & S = P+1 & P >= 0.

if nonvar(P) and not integer(P) then type fail.
if nonvar(S) and not integer(S) then type fail.
if integer(P) then {
if P >= 0 and S unifies with P+1 then succeed else fail
} else
if integer(S) then {
if S > 0 then unify P with S-1 and succeed else fail
} else
instantiation fault.

http://www.cs.cmu.edu/Groups/AI/lang/prolog/doc/standard/okeefe.txt

So my expectation is now:

Jekejeke Prolog 3, Runtime Library 1.3.0
(c) 1985-2018, XLOG Technologies GmbH, Switzerland

?- use_module(library(advanced/arith)).
% 1 consults and 0 unloads in 12 ms.
Yes

?- succ(2,-1).
No

But what is currently implemented in SWI7:

Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.16)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

?- succ(2,-1).
ERROR: Domain error: `not_less_than_zero' expected, found `-1'

burs...@gmail.com

unread,
Jul 6, 2018, 12:52:11 PM7/6/18
to
Does it matter? Yes and No. I noticed that succ/2 is
quite a popular predicate. Besides its popularity,
it can be also used to bootstrap a couple of predictaes.

Richard O'Keefe makes an example. He says:

length([], 0).
length([_|Tail], N) :-
length(Tail, M),
succ(M, N).

http://www.cs.cmu.edu/Groups/AI/lang/prolog/doc/standard/okeefe.txt

Richard O'Keefes definition above will flaunder,
when N is instantiated, but the list isn't, so he gives
even a little better spec, still based on succ,
only with some goal reaordering:

length(List, Length) :-
nonvar(Length),
!,
length_gen(Length, List).
length(List, Length) :-
length_chk(List, Length).

length_chk([], 0).
length_chk([_|Tail], N) :-
length_chk(Tail, M),
succ(M, N).

length_gen(0, []).
length_gen(N, [_|Tail]) :-
succ(M, N),
length_gen(M, Tail).

He also makes an interesting remark: "This is a very
useful predicate, and to get the utmost speed, it might
be coded in the host language, or even in micro-code.
We would like such an implementation to have the best
affordable approximation to its logical semantics."

So I take the above as a kind of implementation spec.
But what if succ/2 has already a different spec. So
length/2 spec is based on succ/2 spec, but succ/2 can
also have different implementations?

Here are two possible outcomes, now based on different succ/2:

Jekejeke Prolog again:

?- [user].
length2([], 0).
length2([_|Tail], N) :-
length2(Tail, M),
succ(M, N).
Yes

?- length2([a,b,c],N).
N = 3

?- length2([a,b,c],-1).
No

SWI7 again:

?- [user].
|: length2([], 0).
|: length2([_|Tail], N) :-
|: length2(Tail, M),
|: succ(M, N).|:
|:
% user://1 compiled 0.00 sec, 2 clauses
true.

?- length2([a,b,c],N).
N = 3.

?- length2([a,b,c],-1).
ERROR: Domain error: `not_less_than_zero' expected, found `-1'

Ha Ha, very funny...

burs...@gmail.com

unread,
Jul 6, 2018, 1:15:33 PM7/6/18
to
Now lets use the longer variant, to figure out
what the outcome of length(L,L) should be. I am
using a var/1 check instead of a nonvar/1 check,
since my Prolog system can index var/1 clauses better.

But the semantics is exactly the same as in
Richard O'Keefe. He also checks the Length argument,
and does the branching based on the Length argument.
So the code we are testing is now:

length2(List, Length) :-
var(Length), !,
length2_chk(List, Length).
length2(List, Length) :-
length2_gen(Length, List).

length2_chk([], 0).
length2_chk([_|Tail], N) :-
length2_chk(Tail, M),
succ(M, N).

length2_gen(0, []).
length2_gen(N, [_|Tail]) :-
succ(M, N),
length2_gen(M, Tail).

Here are the results:

Jekejeke Prolog again:

?- length2([a,b,c],X).
X = 3
?- length2(X,3).
X = [_A,_E,_I] ;
No
?- length2(X,X).
Error: Argument should have evaluable functor, found '.'/2.

SWI Prolog again:

?- length2([a,b,c],X).
X = 3.

?- length2(X,3).
X = [_5122, _5128, _5134] ;
false.

?- length2(X,X).
ERROR: Type error: `integer' expected, found `[_5510]' (a list)

So we have already a length(L,L) error from this
succ based spec. Which is based on an error in the
arithmetic operation inside succ/2.

What does Richard O'Keefe say about arithmetic operations?
Is this error even in the original spirit? Well he had
in mind, that succ/2 throws type errors, he writes:

"Note that determining that there is no solution may
involve detecting a type failure. For example, "succ(a, X)"
has no solution, so the principle says it @i<must> fail,
and the discussion on errors says it @i<may> report a
type failure on the way."
http://www.cs.cmu.edu/Groups/AI/lang/prolog/doc/standard/okeefe.txt

So I have tested length2/2, a bootstrapped predicate,
bootstrapped from succ/2. What do the library or native
predicates actually do? Lets check:

Jekejeke Prolog, I guess I need to work on that:

?- length(X,X).
/* hangs */

SWI7, inconsistent with the -1 (which could be viewed
induced by succ/2) error:

?- length(X,X).
false.

Ha Ha, very funny.

Note: I have an interpretation why the succ/2 solution
can handle length(X,X). Possibly the succ will decide
another direction, different from the intended mode,

and then detect the error. A simple code N is M+1 will
not and cannot detect the same eroror. If N is not a
number usually N is M+1 will simply fail. Hm.

burs...@gmail.com

unread,
Jul 6, 2018, 1:29:45 PM7/6/18
to
Here is what some newcomers do:

O-Prolog Ver 1.07(shizuka)
| ?- length([a,b,c],X).
X = 3;
no

| ?- length(X,3).
no

| ?- length(X,X).
Resource error length(X,X)

So length cannot yet be used in mode length(-,+),
but it does already something for length(X,X).

For Tau Prolog there is a new issue:
https://github.com/jariazavalverde/tau-prolog/issues/28

Ha Ha, I can still generate a sequences of bombs...
I will offer some Swiss Chocolate if there
are no more bombs.

burs...@gmail.com

unread,
Jul 6, 2018, 1:35:27 PM7/6/18
to
Do the newocmers honor popularity of succ/2? I
just saw it used in one of Anne Ogborns tutorial
videos recently.

O-Prolog Ver 1.07(shizuka)
| ?- succ(2,X).
Undefined predicate succ(2,X)

Tau Prolog has implememted it, but not with the
original ROK semantics:

succ(2,-1).
?- succ(2,-1).
uncaught exception: error(domain_error(not_less_than_zero, -1), 'succ/2')
?- succ(X,2).
X = 1.
?- succ(2,X).
X = 3.

burs...@gmail.com

unread,
Jul 6, 2018, 1:42:33 PM7/6/18
to
The succ(2,-1) error message could be viewed by
ROKs own arguments, and is example succ(a,X) as
a further development of succ/2.

But it is not what he wrote as follows:

succ(P, S) <-> integer(P) & integer(S) & S = P+1 & P >= 0.
http://www.cs.cmu.edu/Groups/AI/lang/prolog/doc/standard/okeefe.txt

Maybe such an "evolution" of succ/2 happened
latter. Anybody a reference for this "evolutaion"
of succ/2, when it happened?

ROK writes:
As I said at the beginning, I originally copied
succ/2 from Prolog-X. But in Prolog-X succ(X,Y)
and plus(1,X,Y) were identical. Why the difference?
(Prolog-X has now changed to this definition, I believe.)

So there was already one evolution step, the P>=0,
which is motivated as follows by ROK:

The difference is that plus is for @i<doing arithmetic>,
and succ is for @i<counting things>. If we have plus/3
available, we can use plus(1) whenever we are interested
in adding or subtracting 1 from an arbitrary integer,
and we might as well get some use out of having succ/2
as well. And the use is that a recursive loop using
succ/2 cannot run off to negative infinity.

Hm... to err or not to err...

burs...@gmail.com

unread,
Jul 6, 2018, 4:38:03 PM7/6/18
to
Ok, here is a little surprise. length/2 is not
the only predicate that can hang. Another is
nth0/3. Cheeck for yourself how it hangs in SWI-Prolog:

Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.17)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

?- nth0(2, [a,b,c,d], X).
X = c.

?- nth0(X, [a,b,c,d], c).
X = 2 ;
false.

?- nth0(X, X, c).
ERROR: Out of global-stack.
ERROR: No room for exception term. Aborting.
ERROR: Out of global-stack.
ERROR: No room for exception term. Aborting.
ERROR: Out of global-stack.
ERROR: No room for exception term. Aborting.
ERROR: Out of global-stack.
ERROR: No room for exception term. Aborting.
ERROR: Out of global-stack.
ERROR: No room for exception term. Aborting.
% Execution Aborted

Whats a possible remedy in both cases. Well I
tried succ, I simply replaced some

N is M+1

by the following subgoal:

succ(M, N)

And this is the gratifying result (Preview):

Jekejeke Prolog 3, Runtime Library 1.3.0
(c) 1985-2018, XLOG Technologies GmbH, Switzerland

?- use_module(library(basic/lists)).
% 0 consults and 0 unloads in 0 ms.
Yes

?- length(X,X).
Error: Argument should have evaluable functor, found '.'/2.
length/2

?- nth0(2,[a,b,c,d],X).
X = c

?- nth0(X,[a,b,c,d],c).
X = 2 ;
No

?- nth0(X,X,c).
Error: Argument should have evaluable functor, found '.'/2.
nth0/3

I am now sifting through the code, whether
there are other predicates which could profit
from the succ/2 trick.

burs...@gmail.com

unread,
Jul 6, 2018, 7:58:55 PM7/6/18
to
Different new results.

a) Sometime in the past, negative lengths were allowed:
========================================================

Very difficult what these tests should mean.
I see for example in the Ulrich Neumerkel tests:

length(L,-1).
domain_error(not_less_than_zero,-1)

But then in an old draft:

length(List, -2).
Fails

https://www.complang.tuwien.ac.at/ulrich/iso-prolog/N208

b) succ/2 is very myoptic, see nth0 behaviour (Preview):
========================================================

Jekejeke Prolog 3, Runtime Library 1.3.0
(c) 1985-2018, XLOG Technologies GmbH, Switzerland

?- use_module(library(basic/lists)).
% 0 consults and 0 unloads in 0 ms.
Yes

?- length([_,_|X], X).
Error: Argument should have evaluable functor, found []/0.
length/2

?- nth0(X,[_,_|X],c).
X = 0 ;
X = 1 ;

Ulrich Neumerkel

unread,
Jul 7, 2018, 8:38:44 AM7/7/18
to
burs...@gmail.com writes:
>I have recently added succ/2 to my module arith.
>On purpose I have implemented it *wrongly*. But
>maybe its not that wrongly how implemented it.
...
> ?- succ(2,-1).
> No
>
>But what is currently implemented in SWI7:
>
> Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.16)
> SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
>
> ?- succ(2,-1).
> ERROR: Domain error: `not_less_than_zero' expected, found `-1'

That corresponds to

http://www.complang.tuwien.ac.at/ulrich/iso-prolog/prologue#succ

Only natural numbers (called not_less_than_zero) are intended.
Negative numbers are rather an error.

That's exactly the same situation as arg(-1, s(_), _) and
length(_, -1).

burs...@gmail.com

unread,
Jul 7, 2018, 9:48:01 AM7/7/18
to
arg/3 isn't the best example. Since we have:

?- arg(0, foo(a,b), X).
false.

But the indexes of a compound are always 1,..,n
where n is the arity of a compound.
So its rather arbitrary and inconsequential that
arg/3 and has this error term.

?- catch(arg(-1, foo(a,b), X), error(E,_), true).
E = domain_error(not_less_than_zero, -1).

And not an error term for the zero indiex.
You can check yourself, other languages are
more consequential here:

Val ← 11 33 44 77
Val[1]
11
Val[0]
INDEX ERROR
Val[0]

https://tryapl.org/

So conjecturing from an inconsequential arg/3
to a succ/2 that differs from ROKs original
example doesn't convince me. Although the error
messages is better for succ/2 than for arg/3.

burs...@gmail.com

unread,
Jul 7, 2018, 9:53:09 AM7/7/18
to
Tau Prolog has adopted the inconsequential
arg/3, since it is defined in the ISO core

standard, nevermind I do the same. Here some
newcomer tests, using Tau sandbox:

?- arg(-1,foo(a,b),X).
uncaught exception: error(domain_error(not_less_than_zero, -1), 'arg/3')

O-Prolog has a parsing problem, thats why
a different error message is shown:

O-Prolog Ver 1.07(shizuka)
| ?- arg(-1,foo(a,b),X).
Not an integer arg -1

| ?- integer(-1).
no

burs...@gmail.com

unread,
Jul 7, 2018, 10:07:03 AM7/7/18
to
BTW: I had some fun with between/3. This is
preview of new version of module arith. It
can now do float, float32 and decimal (Preview):

Jekejeke Prolog 3, Runtime Library 1.3.0
(c) 1985-2018, XLOG Technologies GmbH, Switzerland

?- use_module(library(advanced/arith)).
% 0 consults and 0 unloads in 0 ms.
Yes

?- between(1.0, 3.0, X).
X = 1.0 ;
X = 2.0 ;
X = 3.0

?- between(0f1.0, 0f3.0, X).
X = 0f1.0 ;
X = 0f2.0 ;
X = 0f3.0

?- between(0d1.0, 0d3.0, X).
X = 0d1.0 ;
X = 0d2.0 ;
X = 0d3.0

Why not? Float, float3 and decimal are also
exact for some integers, and you can also
count with them.

Same for succ/2 now, even no more lower
bound check (experimental):

?- succ(1.0, X).
X = 2.0

?- succ(X, -0f2.0).
X = -0f3.0

?- succ(0d1.0, X).
X = 0d2.0

He He

My hypothesis: This integer type checks and stuff
are more suitable for Prolog systems without
bignums. But when a Prolog system has bignums,

there is not much gain in restricting many predicates.
The code needs anyway some sophisticate ALU, has
maybe small and big numbers data types side by side,

and needs widening and narrowing internally. So
my current view is a little bit, lets cut off
old plait from non-bignum Prolog systems.

You can also call "Er machte aus der Not eine Tugend."
or "He made a virtue of necessity.". Problem is
these unneceesary checks slow down the code.

There is no really gain anymore in having something
integer, and not number. Since internally integers
and numbers are both objects, and the ALU needs

again to make some type checks. If you want good
code reuse, it doesn't make sense these many checks.
It would only make sense if you have some

code specialization, some automatic code specialization.
But such a specialization can also not take advantage
of primitive data types, since we always want a

continuous view of small and big integers. Obviously
this one:

?- between(1,3,X), write(X), nl, fail; true.
1
2
3
Yes

And this one:

?- A is 1+10^29, B is 3+10^29, between(A,B,X), write(X), nl, fail; true.
100000000000000000000000000001
100000000000000000000000000002
100000000000000000000000000003
Yes

Should seemlessly work.

burs...@gmail.com

unread,
Jul 7, 2018, 10:13:23 AM7/7/18
to
Very funny result in GNU Prolog:

?- X is 2^60-1, succ(X,Y).

X = 1152921504606846975
Y = -1152921504606846976

Ha Ha

burs...@gmail.com

unread,
Jul 7, 2018, 10:28:00 AM7/7/18
to
ROK wrote:

Note: if the implementation does not support bignums, these
predicates can report an integer overflow fault.
http://www.cs.cmu.edu/Groups/AI/lang/prolog/doc/standard/okeefe.txt

Is this an Australian *can*, which is rather a *should*?

Your scribble:
http://www.complang.tuwien.ac.at/ulrich/iso-prolog/prologue#succ

Doesn't say anything about the arithmetic. And
overflow error is not listed. On the other and the
ISO core standard has this more precisely.

In the ISO core standard there are axioms, that
require an overflow error for non-bignumber arithmetic.
Which is not implemented by GNU Prolog.

Now your prologue#succ doesn't have any such axioms.
Its a little a brittle contribution, quite useless.
Same problem with your prologue#between.

Its a little bit useless Tea Party. Lets check
Tau Prolog for this case. In Tau Prolog you
run into floats from integers,

Which is probably and effect of using JavaScript:

?- X = 9007199254740992, succ(X,Y), succ(Z,Y).
X = 9007199254740992,
Y = 9007199254740992,
Z = 9007199254740991.

I have made a picture:
https://gist.github.com/jburse/5136f9ba6b464c4d4d45cdaa3e229a14#gistcomment-2640631

Ulrich Neumerkel

unread,
Jul 7, 2018, 11:01:43 AM7/7/18
to
burs...@gmail.com writes:
>arg/3 isn't the best example. Since we have:
>
>?- arg(0, foo(a,b), X).
>false.
>
>But the indexes of a compound are always 1,..,n
>where n is the arity of a compound.
>So its rather arbitrary and inconsequential that
>arg/3 and has this error term.

No, that case is intended. A frequent pattern used to be:

p(I0, S, ...) :-
arg(I0, S, ...),
!,
...,
I1 is I0-1,
p(I1, S, ...).
p(0, _, ...) :- ...

Ulrich Neumerkel

unread,
Jul 7, 2018, 11:04:58 AM7/7/18
to
burs...@gmail.com writes:
>ROK wrote:
>
>Note: if the implementation does not support bignums, these
>predicates can report an integer overflow fault.
>http://www.cs.cmu.edu/Groups/AI/lang/prolog/doc/standard/okeefe.txt
>
>Is this an Australian *can*, which is rather a *should*?
>
>Your scribble:
>http://www.complang.tuwien.ac.at/ulrich/iso-prolog/prologue#succ
>
>Doesn't say anything about the arithmetic. And
>overflow error is not listed. On the other and the
>ISO core standard has this more precisely.

Exellent observation! Noted.

burs...@gmail.com

unread,
Jul 7, 2018, 12:53:58 PM7/7/18
to
@Ken:
X = -1, should give no for compound and yes
for integer. See also ISO core standard.
There is a special rule for that.

6.3.1.2 Negative numbers

Am Samstag, 7. Juli 2018 15:53:09 UTC+2 schrieb burs...@gmail.com:

burs...@gmail.com

unread,
Jul 7, 2018, 6:52:03 PM7/7/18
to
Monotonocity argumemts doesn't work pro and cons
type checking. They are rather against it.

This here loops, that is correct:
?- length(L, X), L = X.

Now we have also an argument against the
not_less_than_zero error in succ/2:

?- succ(2,-1).
ERROR: Domain error: `not_less_than_zero' expected, found `-1'

?- succ(2,X), X= -1.
false.

The problem is that (=)/2 doesn't respect any types.
So all your type checks can be anihiliated,
by the montonicity argument of yours,

in case you wanted a type check for an output argument.
Because any output argument can be rewritten:

?- p(X1,..,Xn,c).

Into:

?- p(X1,..,Xn,Y), Y=c.

Thats what I explained already a dozen times.
Type checking for output is nonsense.
Another example:


?- length([a,b,c],-1).
ERROR: Domain error: `not_less_than_zero' expected, found `-1'

?- length([a,b,c],X), X= -1.
false.

burs...@gmail.com

unread,
Jul 7, 2018, 10:43:35 PM7/7/18
to
I guess Vienna still doesn't get it, that their
line of output arguments error messsages is complete
nonsense. Here is a new example by Ulrich Neumerkel:

/* which system? looks a little crazy to me */
| ?- char_code(a,-1).
! Representation error in argument 2 of char_code/2
! invalid character code
! goal: char_code(a,-1)
| ?- char_code(a,X), X = -1.
no

I don't think the error you showed makes any
sense. Since the second argument is output, if
the first argument is bound. You can think in modes.
If the mode is (+,-) no need to

check the type of the - argument position. Also
I have never heard something like a modulo
errors excemption. Monotonicity is related to
steadfastness, read ROK,

and it would be wrong if bound output arguments
would lead the predicate into an error path.
Thats conceptually very very wrong. Read ROK about
steadfastness.

Tau Prolog and my system produce another result.
In my opinion the result is sufficient, no need
for some error message terror:

/* Tau Prolog, seems fine to me */
?- char_code(a,-1).
false.
?- char_code(a,X).
X = 97.

For a picture see here:
https://github.com/jariazavalverde/tau-prolog/issues/28#issuecomment-403257248

burs...@gmail.com

unread,
Jul 7, 2018, 10:54:36 PM7/7/18
to
Richard O'Keefe, 2009:
"As the inventor of the term "steadfast" in Prolog programming,
I ought to be in favour of it. Steadfastness basically
means that you cannot force a predicate down the wrong path
by filling in output arguments wrongly."

See also:

Coding Guidelines for Prolog - MICHAEL A. COVINGTON
?- foo(X), X = x.
and
?- foo(x).
must succeed under exactly the same conditions and have the same side effects.
http://www.cs.unipr.it/~bagnara/Papers/PDF/TPLP12.pdf

There is no nonsense with modulo error. It *must*
succeed under exactly the same conditions and have
the same side effects. If succeed is a predication
succ, and the two lines above are 1 and 2, then we
must have:

succ(1) <=> succ(2)

You can check yourself:

p q (p ↔ q)
F F T
F T F
T F F
T T T
http://web.stanford.edu/class/cs103/tools/truth-table-tool/

Either 1 and 2 fail, or either 1 and 2 succeed.
Nothing module errors, or some excemption. Thats
a halucination and confusion of you Ulrich Neumerkel.

burs...@gmail.com

unread,
Jul 7, 2018, 11:24:55 PM7/7/18
to
char_code is also specified with failure,
in the ISO core standard:

8.16.6.1 char_code/2 Description
Procedurally, char,code (Char , Code) is executed as follows:

a) If Char is a variable, then instantiates
Char with the atom whose name (see 6.1.2 b)
is a Character corresponding to the Character
code (7.1.2.2) Code and the goal succeeds,

b) Else if Char is a one-char atom whose
name has a Character code which unifies
with Code, then the goal succeeds,

c) Else the goal fails

Basically the above script first implements
the template char_code(-,+) in a), and then the
template char_code(+,?) in b).

If we take b) literally, the type of Char
is not checked, since unification doesn't
need a type check.

Maybe the template type might lead to
the assumption that output arguments need
also be checked. But I only find:

8.l.2 Template and modes (Page 64)
A specification for both the type of
arguments and which of them shall be
instantiated for the built-in predicate
to be satisfied.

Which can be also read as the type only
documenting, what is outside of the
domain/range of a predicate and hence
will anyway fail. But there is more to
it, effectively errors are also defined:

But finally Note 4 states:

4 When a built-in predicate has a
Single mode and template, an argument
whose mode is ?, and type is not term
is always associated with an error
condition: a type error when the argument
is neither a variable nor of the correct type.

But char_code/2 doesn't have a Single mode.
It has multiple modes. So what is it for
multiple modes.

Note 6 states:

When a built-in predicate has more than one
mode and template, an argument whose mode
is either - or + is always associated with
an error condition: a type error when the
argument is neither a variable nor of the correct type.

So no type error for ? when there are multiple
modes, and this here is correct:

?- char_code(a,-1)
fail

burs...@gmail.com

unread,
Jul 7, 2018, 11:40:51 PM7/7/18
to
You see the principle of a question mark template,
correctly implemented, for functor(+,?,?) which
is also a multi-pattern. You can

check yourself:

Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.1)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

?- functor(1,F,A).
F = 1,
A = 0.

?- functor(1,g(b),_).
false.

?- functor(f(a),F,A).
F = f,
A = 1.

?- functor(f(a),g(b),_).
false.

According to the wrong Vienna Ulrich Neumerkel
doctrine, the second and fourth query would need
to throw an error. But they don't.

I didn't read the use case of functor/3 in the
ISO core standard, but from the template, the
above seems ok, although in the template

the type is functor(nonvar,atomic,integer).
But g(b) is not atomic, but since it is ?,
no error is needed.

Here is a little glitch in GNU Prolog, same
queries as in SWI-Prolog, but different
outcome:

GNU Prolog 1.4.4 (64 bits)
Compiled Apr 23 2013, 17:26:17 with /opt/local/bin/gcc-apple-4.2

?- functor(1,F,A).
A = 0
F = 1
yes

?- functor(1,g(b),_).
no

?- functor(f(a),F,A).
A = 1
F = f
yes

?- functor(f(a),g(b),_).
uncaught exception: error(type_error(atom,g(b)),functor/3)

Ha Ha, surprise, surprise, bad implementation
of functor/3 in GNU Prolog.

burs...@gmail.com

unread,
Jul 7, 2018, 11:55:43 PM7/7/18
to
The example type error given in the ISO
core standard, is correct, since it is
the other mode functor(-,+,+):

functor(F, foo(a), 1)
type_error(atomic, foo(a))

You need to look at the modes, and if its
a multi-mode and its a ? position, you don't
need to check some types.

There are more predicates where you accept
this very naturally, for example =..(+,?).
Do you want to type check lists for the

univ predicate? Lets make a test what Prolog
systems do. Maybe there is a crazy Prolog system.
Here is what I think the ISO core standard allows:

Jekejeke Prolog 2, Runtime Library 1.2.7
(c) 1985-2018, XLOG Technologies GmbH, Switzerland

?- f(a) =.. L.
L = [f,a]

?- f(a) =.. g(b).
No

But SWI7 does a check, which is in my opinion
unnecessary, not implied by the standard:

Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.1)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

?- f(a) =.. L.
L = [f, a].

?- f(a) =.. g(b).
ERROR: Type error: `list' expected, found `g(b)' (a compound)

The standard also doesn't have a single test
case for such an error. All the list error
test cases are for mode =..(-,+) which is legit.

You can check yourself the exmples in the ISO
core standard with a list error are all mode =..(-,+).
Pure accident? No. You don't need errors for

mode =..(+,?). Because of steadfastness. An
output argument of type ? of a muti-moded
predicate is steadfast, because ?

doesn't check argument types.

burs...@gmail.com

unread,
Jul 8, 2018, 12:01:49 AM7/8/18
to
Ha Ha, because everybody interprets the
templates differently, especially the ? mode,
we have now:

Tau Prolog:

?- functor(1, g(b), A).
uncaught exception: error(type_error(atomic, g(b)), '/'(functor, 3))

SWI-Prolog:

?- functor(1,g(b),_).
false.

GNU-Prolog:

?- functor(1,g(b),_).
no

Ha Ha, what a mess!

Am Sonntag, 8. Juli 2018 05:40:51 UTC+2 schrieb burs...@gmail.com:

burs...@gmail.com

unread,
Jul 8, 2018, 6:11:53 AM7/8/18
to
Hi Ulrich,

I have rolled back my changes to length/2. I think
your observation in the Tau Prolog issue, that both:

?- length(X, L), X = L.

And:

?- length(X, X).

Can loop, tells me aswell that looping is ok. But
since the predicate is tail recursive, it will not
consume a lot of stack, and loop quite long,

but its still interuptible, since it is written
in Prolog, so it responds to thread signal. For
a more low level implementation, the

loop might be a vulnerability, since it might
possibly crash the system. So a SWISH length(X,X)
might really be a problem for the system. Not sure.

Concering your:
http://www.complang.tuwien.ac.at/ulrich/iso-prolog/prologue#succ

I have now changed my succ/2 implementation again.
You see you document these modes as follows:

succ(+integer,?integer)
succ(-integer,+integer)

I have implemented them now similar to char_code/2,
as in the ISO core standard, how the use case is documented.
I had the modes differently so far. Which means:

a) I first check the mode succ(-,+), i.e.
simply whether the first argument is a variable.
And then a type check (in my case more broader
number, but thats another issue) happens.

b) Then I work on the mode succ(+,?). But here
there is only one type check for the first
argument (in my case more broader number,
but thats another issue) and then
unification happens.

With interpreting the modes as in char_code/2,
I still get the following, no error message but
steadfastness:

Jekejeke Prolog 3, Runtime Library 1.3.0
(c) 1985-2018, XLOG Technologies GmbH, Switzerland

?- succ(1,-1).
No

?- succ(1,X), X= -1.
No

The rework will have a blip more speed, since
testing var(A) instead of var(B), is faster concerning
the var indexing I have, since it is the first

argument and not the second argument. So the index
lookup is always faster in the argument with lower
argument numbers than in the arguments with higher

argument numbers, since my JIT-ter works left to right.

Oki, Doki. Interesting.

burs...@gmail.com

unread,
Jul 8, 2018, 6:25:42 AM7/8/18
to
You see what the loop does to a JavaScript
based Prolog system here. The Browser I was
using reported a non-responding script:

Screenshot of Browser response:
https://github.com/jariazavalverde/tau-prolog/issues/28#issue-339016874

I don't know what other Browsers do, the
above is from the Mozialla Family of browsers.
Typically Browsers try not to crash and

keep responsivity. But node.js migtht again
react differently. This is something which
the JavaScript Prolog implementor has to

think over. A simple solution for an only
Prolog system could be also that it proves
a max inference parameter and an inference counter,

so that also other queries are killed if they
run too lonk. A previous release 1.2.6 I have
even implemeted a thread eviction strategy

for my Prolog system. It has now a framework,
but the metric is not yet further evolved. So
far I use a metric for my constraint solvers,

and kill the thread the most thread local
clauses. I am really currious how these web
based Prolog systems will evolve, and whether

they will delegate everything to the Browser,
or add something to the Prolog interpreter.
Already a standard Prolog interpreter, since

it understands thread signals, and supports
Ctrl-C, often does more than the bare Operating
system. But inside a browser the runtime environment

is not anymore a bare Operatoring system, with
the usual Unix signals and stuff. I am not a
JavaScript expert, but I guess I will try some

more bombs in the future...

burs...@gmail.com

unread,
Jul 8, 2018, 6:26:54 AM7/8/18
to
Corr.:
Prolog system could be also that it provides
a max inference parameter and an inference counter,

Ulrich Neumerkel

unread,
Jul 8, 2018, 9:44:40 AM7/8/18
to
burs...@gmail.com writes:
>char_code is also specified with failure,
>in the ISO core standard:
>
>8.16.6.1 char_code/2 Description
>Procedurally, char,code (Char , Code) is executed as follows:
>
>a) If Char is a variable, then instantiates
>Char with the atom whose name (see 6.1.2 b)
>is a Character corresponding to the Character
>code (7.1.2.2) Code and the goal succeeds,
>
>b) Else if Char is a one-char atom whose
>name has a Character code which unifies
>with Code, then the goal succeeds,
>
>c) Else the goal fails

The description of the built-in predicate assumes that no
error condition is satisfied, ...

And there is error condition 8.16.6.3 d (which, btw. needs
a further requirement that the argument is an integer).

>When a built-in predicate has more than one ...

All these are notes. See 1.1 Notes for their purpose.

Many systems agree to produce a representation error for
char_code(a, -1). Like SICStus, GNU, X, IF, ECLipse iso.

SWI produces a type_error(character_code,C) for smaller
integers, and a representation_error(int) for larger
integers.

burs...@gmail.com

unread,
Jul 8, 2018, 2:34:29 PM7/8/18
to
The notes explain the error system of
the templates. Do you see some other purpose?

If I read the notes correctly, ? is left out
for multiple mode predicates. So it would be

leggit to not bother with errors in this
situation. Since it is not mandatory.

Ulrich Neumerkel

unread,
Jul 9, 2018, 1:29:53 AM7/9/18
to
burs...@gmail.com writes:
>The notes explain the error system of
>the templates. Do you see some other purpose?

It all depends on what you understand by explain.
But in any case a note is not normative.

>If I read the notes correctly, ? is left out
>for multiple mode predicates. So it would be
>leggit to not bother with errors in this
>situation. Since it is not mandatory.

A note cannot make anything mandatory.

What is mandatory are the x.y.3 Errors subclauses and
to a certain extent 7.12.2 Error classification.

burs...@gmail.com

unread,
Jul 9, 2018, 8:20:56 AM7/9/18
to
There are two error systems, the templates
and the x.y.3 list. Maybe not done by the
same authors.

The templates automatically define some errors,
since they have mode and type. The x.y.3 lists
are redundant.

Only in some cases the x.y.3 lists add something
to the built-in, like a division by zero is
not a template based error.

That the x.y.3 lists repeat the template induced
errors blows the standard up. It is also tempting
to ignore the template semantics.

burs...@gmail.com

unread,
Jul 9, 2018, 8:49:32 AM7/9/18
to
The problem is that Prolog doesn't have types. There
is only the Herbrand domain and predicates define
a relation of the Herbrand domain.

So mostlikely the template system in the ISO core
standard was borrowed from an existing system, without
observing that the types are essentially not part of

Prolog. You can do that in a Prolog system that really
has types. An old example being Turbo Prolog. There
you had types and modes. For example an external

predicate could be defined:

global predicates
double(integer,integer) - (i,o) language assembler

an then implemented via assembler:

MOV AX,[BP]+6 ;get the value to which
;MyInVar is bound
ADD AX,AX ;double that value
LDS SI,DWORD PTR [BP]+6 ;Store the value to
;which MyOutVar is to
;be bound in the
;appropriate address.
MOV [SI],AX

http://bitsavers.informatik.uni-stuttgart.de/pdf/borland/turbo_prolog/Turbo_Prolog_Owners_Handbook_1987.pdf

So the extrem in the above is even that the FFI
would provide a value holder to the built-in.
What I don't know whether Turbo Prolog then

only allowed a call with a variable in the second
argument, or whether the Prolog system itself
allowed calling it with a constant and then

translate it to what? Outside of Turbo Prolog
in other Prolog system, where there are no types
a call as follows would be possible:

double(2,1.0)

This could be translated to (because the FFI has an out):

double(2,X), X = 1.0 /* variant 1 */

But what you are telling me, Ulrich Neumerkel, is
the following, that the above should be translated
into the below:

Y = 1.0, must_be(integer,Y), double(2,X), X = Y. /* variant 2 */

which is a little bit nonsensical, on two grounds:

1) Its a runtime check, this check could be also
done at compile time.

2) Even if some checks would be done at compile time,
because Prolog is not Turbo Prolog, still a runtime
check would be neded. But this costs you time.

If your system has for example small integer and
big integer, you need to test 2 type tags. You also
need to dereference the must_be argument.

So this Ulrich Neumerkel nonsense slows down a
Prolog system for no reason. A Prolog system doesn't
have types. You do not need to check the type of

output arguments. Thats against steadfastness,
and makes absolutelutely no sense and only cost
precious performance.

If somebody implements all the Ulrich Neumerkel error
check proposals, the result will be a Prolog system
that runs on valium and not on stereoids.

Some of the types you cannot check in O(1), like
for example the list type, this needs O(n) time.
If you have a typesystem based Prolog system,

like Turbo Prolog type conformance is checked
at compile time, and no more type checks are needed
at runtime. But Prolog system without types,

might unnessariely be slowed down. Its a simple
calculuation, a Prolog code location in a loop is
like 1000 time or more seen at runtime,

at compile time such a Prolog code location is
only seen once. So every type check you add to
the Prolog interpreter, and which is most of

the times anyway satisified, only slows down
the code proportional to the runtime. Thats just
crazy nonsense to check the type of output

arguments. Show me a paper where it is documented
that this nonsense overhead can be eliminated?

burs...@gmail.com

unread,
Jul 9, 2018, 9:17:09 AM7/9/18
to
BTW: double/2 is an interesting case. The aftermath
of Turbo Prolog, so to speek, the math after Turbo
Prolog, with big numbers, we might provide

double_chk/2 with mode (i,i)

final int compareHalf(MutableBigInteger b) {
https://github.com/tbuktu/bigint/blob/master/src/main/java/java/math/MutableBigInteger.java#L312

In this case, if there is also mode (i,i) around,
we would do maybe more checks. But it would be more
a var/1 check not must_be/2 check first.

Somehow I live currently in a world, where
builtins are realized as follows:

Step 1: mode branching
Mostoften only var/1 checks. Has even support
in my multi-argument indexing, in case the mode
branching is realized in a couple of clauses.

Step 2: type checking, *only* input
Type is only checked for input. After the mode
branching. Often for the type checking there
is not much alternative, atom_codes, should
produce codes of an atom, so we check for the
first argument being an atom.

The ISO core standard doesn't have mode/type templates
that completely reflect what is going on in the use
cases. For example char_code(+,?) is ok, this is
documented in the use case of the predicate char_code/2.

But for atom_codes something else is in the use case
than in the modes. We find in the modes of atom_codes:

atom_codes(-,+)
atom_codes(+,?)

But the use case says something else, namely this
template, which is slightly something else:

atom_codes(-,+)
atom_codes(+,-)
atom_codes(+,+)

You can check yourself:

8.16.5.1 Description

a) If Atom is a variable, then
instantiates Atom with the atom
whose name (see 6.1.2 b) is a
sequence of characters such
that the Character code (7.1.2.2)
of the Nth Character is the
Nth element of List, and
the goal succeeds,

b) Else if List is a variable,
then instantiates List with a
list of Character Codes such
that the Nth element of List
is the Character code of the
Nth Character of the name of
Atom, and the goal succeeds,

c) Else if List is a list of
Character Codes, and Atom is an
atom whose name is a sequence of
characters such that the Character
code of the Nth Character is the
Nth element of List, then the
goal succeeds,

d) Else the goal fails.

Now here is a little quizz. To which branch
of the above use case belongs this call:

?- atom_codes(abc,[X|Y]).
X = 97,
Y = [98, 99].

Its neither b) nor c), so accoding to the ISO core
standard, it should fail, or maybe throw an error?

Ha Ha

burs...@gmail.com

unread,
Jul 9, 2018, 9:20:26 AM7/9/18
to

burs...@gmail.com

unread,
Jul 9, 2018, 9:35:14 AM7/9/18
to
We only know that atom_codes/2 can do more
from one example:

8.16.5.4 Example

atom_codes('North', [0'N|X]).
Succeeds, unifying X with
[0'o, 0'r, 0't, 0'h]

The errors don't tell us more, there two
errors, that deal with lists, but its for
both situations mode atom_codes(-,+).

8.16.5.3 Errors

a) Atom is a variable and List is a
partial list or a list with an element which is a variable
- instantiation-error.

c) Atom is a variable and List partial list
- type-error(list, List).

So the node atom_codes(+,?) is not documented
as having an error in the section x.y.3. Lets
see what Prolog systems do:

SWI7, no error, treated as output, no type checking:

Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.1)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

?- atom_codes(abc,[X|Y]).
X = 97,
Y = [98, 99].

?- atom_codes(abc,[X|c]).
false.

GNU-Prolog, although not documented in the ISO core standard,
in the Ulrich Neumerkel x.y.3 section for atom_codes/2, see
previous remarks, GNU Prolog throws an error:

GNU Prolog 1.4.4 (64 bits)
Copyright (C) 1999-2013 Daniel Diaz

?- atom_codes(abc,[X|Y]).
X = 97
Y = [98,99]

?- atom_codes(abc,[X|c]).
uncaught exception: error(type_error(list,[_282|c]),atom_codes/2)

Interesting, surprise. I wanted to dig up atom_codes/2
already yesterday. But didn't have time. But well I
guess this proves that none of the following parts

of the ISO core standard:
- templates
- use case
- error list

usually define a predicate as found in an implementation.

Ulrich Neumerkel

unread,
Jul 9, 2018, 2:08:01 PM7/9/18
to
burs...@gmail.com writes:
>You can check yourself:
>
>8.16.5.1 Description
>
...
>c) Else if List is a list of
>Character Codes, and Atom is an
>atom whose name is a sequence of
>characters such that the Character
>code of the Nth Character is the
>Nth element of List, then the
>goal succeeds,
>
>d) Else the goal fails.
>
>Now here is a little quizz. To which branch
>of the above use case belongs this call:
>
> ?- atom_codes(abc,[X|Y]).
> X = 97,
> Y = [98, 99].
>
>Its neither b) nor c), so accoding to the ISO core
>standard, it should fail, or maybe throw an error?

8.16.5.1 c has been replaced in Cor.1. Please consult it.

Ulrich Neumerkel

unread,
Jul 9, 2018, 2:12:42 PM7/9/18
to
burs...@gmail.com writes:
>GNU-Prolog, although not documented in the ISO core standard,
>in the Ulrich Neumerkel x.y.3 section for atom_codes/2, see
>previous remarks, GNU Prolog throws an error:
>
> GNU Prolog 1.4.4 (64 bits)
> Copyright (C) 1999-2013 Daniel Diaz
>
> ?- atom_codes(abc,[X|Y]).
> X = 97
> Y = [98,99]
>
> ?- atom_codes(abc,[X|c]).
> uncaught exception: error(type_error(list,[_282|c]),atom_codes/2)

Please refer to Cor.2. All corrigenda are downloadable
for free. Or just read:

http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#C10

burs...@gmail.com

unread,
Jul 9, 2018, 4:11:42 PM7/9/18
to
But the template was not changed. The template,
one mode of it, is still atom_codes(+,?).

So new error c) doesn't apply. SWI7 behaviour
should be allowed.

burs...@gmail.com

unread,
Jul 9, 2018, 4:19:35 PM7/9/18
to
Some predicates, the mode was changed, or
lets say for an output argument, not like
for other predicates (+,?), something else

was used. Example:

sort(@list, -list)
sort(+list, +list)

Again not adopted by Prolog systems:

Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.1)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

?- sort([a,b,c],[X|Y]).
X = a,
Y = [b, c].

?- sort([a,b,c],[X|c]).
false.

On the other hand:

GNU Prolog 1.4.4 (64 bits)
Copyright (C) 1999-2013 Daniel Diaz

?- sort([a,b,c],[X|Y]).
X = a
Y = [b,c]

?- sort([a,b,c],[X|c]).
uncaught exception: error(type_error(list,[_282|c]),sort/2)

burs...@gmail.com

unread,
Jul 9, 2018, 5:11:37 PM7/9/18
to
That the atom_codes/2 is just some crazy stuff,
the way the use case was defined, and then DTC1
and DTC2, you also see in how ROK conceived it:

ROK wrote:

@Begin[Hunk]
atom_chars(Atom, ListOfChars) :-
nonvar(Atom),
atom_string(Atom, String),
string_chars(String, ListOfChars).
atom_chars(Atom, ListOfChars) :-
var(Atom),
string_chars(String, ListOfChars),
atom_string(Atom, String).
@End[Hunk]
http://www.cs.cmu.edu/Groups/AI/lang/prolog/doc/standard/okeefe.txt

There was never a use case branch that checked
for var(List), as in the ISO core standard branch b)
and there was never a branch c), with some

non-functional optimization. You can check
the ROK source yourself.

What are non-functional requirements (NFRs):
https://en.wikipedia.org/wiki/Non-functional_requirement

Disclaimer: I only stepped by accident just
now on the ROK @Begin[Hunk] @End[Hunk]. But the
above is what needs to be put in a standard

as a specification. No need to put more in
a standard, and then make some NFR based errors
mandatory. Thats makes absolutely no sense.
Message has been deleted

Mostowski Collapse

unread,
Jan 2, 2020, 9:26:20 AM1/2/20
to
Now finally, after 2 months of thinking and considering
ultra complicated abstract interpretation lattices,
I now got an idea how to also support nonvar/1 during

body equation indexing. Body equation indexing is also
the basis for my var/1 indexing. It is based on the
following paper:

Step 2.2.2 of algorithm I of:
Demand-Driven Indexing of Prolog Clauses
Vıtor Santos Costa, Konstantinos Sagonas, and Ricardo Lopes
http://user.it.uu.se/~kostis/Papers/iclp07.pdf

The clauses remain completely untouched, but some code
inspection is done. All you do is you give the clause
indexer some additional smarts to find the indexing key.
Usual indexing just looks at the argument and finds
the indexing key as follows:

key?
|
v
p(BigTerm, ...) :- ... BigTerm ...

For term sharing the clause is not modified, nothing
is moved into the head. The clause is used as is
to find the indexing key through code inspection.
This is the adaptation for my Prolog system. What
was a register in the ICLP07 paper is now a variable:

+--------+
key? | key?
| | |
v | v
p(Var, ...) :- Var = BigTerm ... Var...
| |
+----------+

var/1 indexing is based on considering var/1 instead
of (=)/2 in the body. We further also support functor/3
in the body. But there was no support for nonvar/1 so far.

j4n bur53

unread,
Jan 2, 2020, 9:37:28 AM1/2/20
to
So how will we handle nonvar/1. Well the solution
is quite simple. At the moment the recognized body
conditions by the clause inspection based indexer

do also mark the end where clause inpection stops.
So basically we only scan an initial segment of
a body as far as the body conditions are concerned:

Head :- ( IndexableCondition )* ( OtherwiseLiteral )*
\-- only this part ---/
is analyzed

One of the main problems we are facing is for
example that this one doesn't get indexed, because
the clause inspection already stops at nonvar:

/* from module "simp" */
goal_simplification((U,C), J) :-
nonvar(U), /* clause inspection stops here */
U = (A,B),
simplify_goal((B,C), H),
simplify_goal((A,H), J)

So we have a missed opportunity U = (A,B) and a
missed indexing key ','. The solution is darn simple,
just add nonvar/1 to the indexable conditions,

but do nothing with it. With this very small tweak a
larger initial segment of a body will be analyzed
and we get a little better indexing:

/* from module "simp" */
goal_simplification((U,C), J) :-
nonvar(U),
U = (A,B),
simplify_goal((B,C), H), /* clause inspection stops here */
simplify_goal((A,H), J)

Its not what we had in mind. We were expecting we could
do more for nonvar/1. But it nevertheless is an improvement
since it will allow the indexer to gather more indexing keys.

Mostowski Collapse schrieb:

Mostowski Collapse

unread,
Jan 2, 2020, 11:12:35 AM1/2/20
to
As a non-functional property the sharing is
observable. You can try the following:

p(A, B, C, D, E) :-
D = f(E,E,E,E),
C = f(D,D,D,D),
B = f(C,C,C,C),
A = f(B,B,B,B).

If you do a Logtalk source transformation
you get a clause of size 4^4+4^3+4^2+4^1 = 340
memory cells. If you don’t do a Logtalk source
transformation you get a clause of size 5*4 = 20
memory cells.

Same for the runtime, i.e. the thread time use
by calling for example:

?- p(Y, _, _, _, X).

I didn’t test yet, since I don’t have a souce
transformer. Maybe I can add some timing comparison
by using a manual transformation. This is observable
if the Prolog system doesn’t apply some common
subexpression elimination while compiling clauses.

Common subexpressions elimination would possibly
need hash calculation and 340 head searches, and
would slow down assert and retract, so I don’t
have this. Thats why I call it explicit sharing.
Its not an automatism. Its something that the
programmer can do by using (=)/2.

A modified Logtalk transformation could possibly
only move the terms to the head up to some depth.
But to not negatively affect deep indexing it
would need some good heuristics here. This is
not yet a problem in my Prolog system, since I
don’t have yet deep indexing.

Edit 02.01.2019:
Here are some timings, pretty much the ratio
340 cell/20 cell from slow to fast:

Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.16)

/* with sharing */
?- time((between(1,1000000,_),p(Y,_,_,_,X),fail;true)).
% 1,999,999 inferences, 0.266 CPU in 0.254 seconds (104% CPU, 7529408 Lips)
true.

/* without sharing */
?- time((between(1,1000000,_),p2(Y,_,_,_,X),fail;true)).
% 1,999,999 inferences, 3.297 CPU in 3.289 seconds (100% CPU, 606635 Lips)
true.

I used the following manually transformed p/5:

?- listing(p2/5).
p2(f(f(f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A))), f(f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A))), f(f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A))), f(f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)))), f(f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A))), f(f(A, A, A, A), f(A, A, A, A), f(A, A, A, A),
f(A, A, A, A)), f(A, A, A, A), A).

Kin Taylk CalocaleurlgurrIzzly NONturnEYEmation

unread,
Jan 8, 2020, 1:25:17 AM1/8/20
to
<blockquote/cite=j...@nuthouse.global>
<xmp>

succ(P, S) <-> integer(P) & integer(S) & S = P+1 & P >= 0

</xmp>
</blockquote>

<xmp>

(term_expansion((A <=> B :- C),(term_expansion(A,B) :- C))) .

(term_expansion((A <-> B :- C),(goal_expansion(A,B) :- C))) .

</xmp>

~~~ kintalken ~~~

Kin Taylk CalocaleurlgurrIzzly NONturnEYEmation

unread,
Jan 8, 2020, 1:31:00 AM1/8/20
to
|]> integer(P) & integer(S)

:- op(10'1125,'yfx','&') .

goal_expansion((A & B),(B , C)) .

Yer a right dominant left begets right top dominates bottom obbsesiv bekauz human so relax and let the robot suggest the alternative available in some small measure ?

~~~ kintalken ~~~

Kin Taylk CalocaleurlgurrIzzly NONturnEYEmation

unread,
Jan 8, 2020, 1:41:37 AM1/8/20
to
Ulrich Neumerkel wrote :

A frequent pattern used to be :

<xmp>

p(I0, S, ...) :-
arg(I0, S, ...),
!,
...,
I1 is I0-1,
p(I1, S, ...).
p(0, _, ...) :- ...

</xmp>

very interesting .

But better if the base case
is above (thus is first performance) , and it is much better if the base case is that which contains the kut! .

a kut! in the base case is perhaps an _enhancement_ to logikal puritea ?

~~~ kintalken ~~~

Mostowski Collapse

unread,
Jan 8, 2020, 4:01:26 AM1/8/20
to
The Logtalk succ/1 is the best succ/1.

LoL

Mostowski Collapse

unread,
Jan 8, 2020, 4:09:19 AM1/8/20
to
Corr.:
The Logtalk succ/2 is the best succ/2.

Interestingly this here works in my system:

Jekejeke Prolog 4, Runtime Library 1.4.1 (12 November 2019)

?- use_module(library(advanced/arith)).
% 1 consults and 0 unloads in 28 ms.
Yes

?- X is succ(3).
X = 4

I guess thats why I wrote succ/1
instead of succ/2 by accident.

Mostowski Collapse

unread,
Jul 20, 2020, 5:10:41 AM7/20/20
to
Its summer again. Lets do something for clause
indexing again. It currently emerges for my system
that I need deep indexing.

The problem are objects. If I register only
the ID of an object, I will loose the class
information. So if I replace this here:

name(beagle(1000), sara).
name(rottweiler(1001), apollo).

By this here in favor of indexing:

name(1000, sara).
name(1001, apollo).

I am loosing type information. Like if I would
like to do a backward lookup from name to object,
calling ?- name(Dog, apollo).

So I am in desperate need of deep indexing now.
It would really complement indexing, and it seems
now unavoidable.

Mostowski Collapse

unread,
Jul 20, 2020, 5:16:06 AM7/20/20
to
A second idea, an old idea, are clauses with
multiple entry points. Typically a neck cut
can be skipped if indexing delivers anyway

only one clause. So if we have the following
clause in our system:

... :- !, A.

when indexing delivers us anyway only once
clause, we wont create a choice point,

and the cut would have nothing to do. We could
extend this to the case where B is some guard,
namely if the clause has this form:

... :- B, !, A.

We could compile an alternative form as well:

... :- B, A.

And then use the alternative form if indexing
tells us that there is no choice point. But instead
of compiling an alternative form, we could

also compile a branching form where two different
entry points share some common code, namely the
A. So the clause would be compile to something like:

entry 1: B
!
goto common
entry 2: B
common: A

This should be also possible in my system, since
a clause body is a linked list of literals.
And we could also make forked linked lists.

Mostowski Collapse

unread,
Jul 20, 2020, 5:21:02 AM7/20/20
to
SWI-Prolog has a notion of guard. SWI-Prolog
lists primitive type tests (atom/1, integer/1, etc),
comparison ( ==/2 , @>/2 , >/2 , etc.).

Maybe we need to exclude (=)/2 from the list of
recognized guards. My suspicion is that it needs to
be missing because unify hook can cause a choice point.

Some Prolog systems block unify hooks while checking
guards, for example ECLiPSe Prolog. Not sure, its
documented. They do this exactly to allow certain

optimizations, but it might change attributed variable
semantics slightly. Especially when unify hooks are
blocked until after a cut. I have (=)/2 on the

list of indexing guards but it might then not
anymore be found on the list of skipping guards.
Also skipping guards might again have more

on the list like atom/1, integer/1, which do
currently not help my indexing. What helps is
for example (=)/2, functor/3, etc... So we might

have skipping guards and indexing guards, and
the skipping guards would guide a new two entry
compilatio. Why not, lets see...
0 new messages