When are functional notation of dict compile time expanded?

Hello,

I tried to use the library arithmetic_types which does compile time expansion of user defined arithmetic predicates with dicts but it doesn’t work.
Basically, compile time expansion of dicts apply earlier than arithmetic_types, which blocks arithmetic_types to do its own compile time expansion.

Here is a more detailed example: Arithmetic type and swi-prolog dicts mix badly · Issue #8 · ridgeworks/arithmetic_types · GitHub

:- use_module(library(arithmetic_types)).
:- arithmetic_function('.+'/2).

test_pred(Y) :-
   X = array{}.arange(10),
   Y is (X .+ X).to_list().

And the resulting program:

?- listing(test_pred).
array:test_pred(Y) :-
    '.'(array{}, arange(10), A),
    X=A,
    '.'(X.+X, to_list(), B), % X .+ X should have expanded into its own goal
    Y is B.

Would this problem be fixable ?

I answered this on the referenced GitHub issue, but in case there’s a wider community of interest:

library(arithmetic) uses goal expansion to support user defined arithmetic functions. In general terms it lifts any user defined functions out of the is (or related arithmetic comparisons) but leaves things it deems “evaluable”, like numbers, character codes, etc. alone. The ‘.’ functional notation is deemed evaluable, so no further internal expansion of any arguments is done. The entire ‘.’ sub-expression is actually lifted and expanded by the dictionary support code, which explains the actual code listed after expansion. At least, that’s my understanding.

I am responding here instead of in the github issue since this is more of a discussion and so that other people can weigh in.

You are right.
Trying to comment these lines:

evaluable(Func) :-                   % Functional notation.
	functor(Func, ., 2),
	!.

makes code like this:

:- use_module(library(arithmetic_types), []).

main(A, B) :-
   A is B+1.

go into a stack overflow at compile time:

ERROR: /home/kwon-young/prog/array/test_module.pl:3:
ERROR:    Stack limit (1.0Gb) exceeded
ERROR:      Stack sizes: local: 6Kb, global: 0.8Gb, trail: 0Kb
ERROR:      Stack depth: 35,975,343, last-call: 100%, Choice points: 19
ERROR:      In:
ERROR:        [35,975,343] arithmetic_types:evaluable(_215852598)
ERROR:        [51] '$apply':forall('<garbage_collected>', <compound (:)/2>)
ERROR:        [50] arithmetic_types:evaluable('<garbage_collected>')
ERROR:        [49] arithmetic_types:do_expand_function(<compound (+)/2>, <compound (+)/2>, true)
ERROR:        [48] arithmetic_types:expand_function('<garbage_collected>', '<garbage_collected>', _215852698)

The weird thing is I have no idea why the ‘.’ functional notation is even used here ?

The goal expansion of is still has to test for ‘.’ even though it may not be present in the source expression. The overflow occurs because the original clause you commented out prevented reaching a subsequent clause with an unexpected argument type, and I should close that loophole.

Of course you’re free to modify the code but you should be prepared to debug the result.

Ah, thank you.
I didn’t know if I was hitting a bug in arithmetic_types or if it was by design.

I’ll try to experiment on my side to see if I can correctly integrate dict functional notation with arithmetic_types.
If I manage to find something useable, I will let you know.