Dicts, attribute variables and cyclic terms

Functional notation expansion is in boot/expand.pl.

Before making that possible, it should be clear what you want to achieve and that there is no reasonable alternative to achieve that. So far I’ve seen some snippets, but I was rather unsure what I was looking at.

So here I made some examples to remember what was actually the problem:

#!/usr/local/bin/swipl -s

test_001 :- true
, L = [ #{a:1}, #{a:2}]
, bagof( M.a, member( M, L), L2)
.

test_002 :- true
, L = [ #{a:1}, #{a:2}]
, D = #{a:_}
, bagof( M.a, ( D = M, member( M, L)), L2)
.

test_003 :- true
, L = [ #{a:1}, #{a:2}]
, D = #{a:_}
, bagof( M.a, ( member( M, L), M >:< D), L2)
.

test_004 :- true % works
, L = [ #{a:1}, #{a:2}]
, D = #{a:_}
, bagof( D.a, ( member( M, L), M >:< D), L2)
.

test_005 :- true
, L = [ #{a:1}, #{a:2}]
, bagof( M.a, ( member( M, L), M >:< #{a:_} ), L2)
.

test_006 :- true % works
, L = [ #{a:1}, #{a:2}]
, bagof( A, ( member( M, L), A = M.a ), L2)
.

test_007 :- true
, L = [ #{a:1}, #{a:2}]
, TERM1 = member( M, L)
, TERM2 = M.a
, bagof( TERM2, TERM1, L2)
.

test_008 :- true
, L = [ #{a:1}, #{a:2}]
, TERM1 = member( M, L)
% , TERM2 = M.a
, atom_to_term( 'M.a', TERM2, Vs), member( 'M'=M, Vs)
, mi( bagof( TERM2, TERM1, L2), T)
, T
, writeln( L2)
.

mi( bagof( T, G, L), TERM) :- true
, mi(T, T1-T2)
, TERM = bagof( T2, T1^(G, T1), L)
.

% mi( D.K, T1-T2) :- T1 = get_dict( K, D, T2) . % error when called
mi( D+K, T1-T2) :- T1 = get_dict( K, D, T2) .

test_009 :- true % works
, L = [ #{a:1}, #{a:2}]
, TERM1 = member( M, L)
% , TERM2 = M.a
, atom_to_term( 'M+a', TERM2, Vs), member( 'M'=M, Vs)
, mi( bagof( TERM2, TERM1, L2), T)
, T
, writeln( L2)
.

From that 9 examples 3 work and the last uses a simplified metainterpreter.
In the test_009 I switched from ‘.’ to ‘+’ to make it work. test_008 could work if I were able to temporarily disable a specific portion of the expansion rules (I don’t know which one exactly because there are more). It could actually also be possible to disable the expansion mechanisms at all while mi is running.

Fine, but what is this expected to do? Do you expect L2 to hold [1,2]? Or maybe [#{a:1}.a, #{a:2}.a]? In any case, the first argument of bagof/3 is not a meta argument
and this is thus equivalent to this body, clearly resulting in an instantiation error.

     L = [ #{a:1}, #{a:2}],
     Tmp = M.a,
     bagof(Tmp, member(M, L), L2)

What works is

t(L2) :-
    L = [ #{a:1}, #{a:2}],
    bagof(X, (member(M, L), X = M.a), L2).

My advice is to avoid functional notation when meta-predicates are involved. The rule is that the system will apply goal expansion to the meta-argument.