Improving usability of dicts

I was thinking maybe the following could improve usability on dicts using the functionality that we already have with select_dict/3.

  1. To allow partial unification in the head using this syntax:
mypred( mydict{ key1: Val1, key2: Val2, ...} ) :-
   % here the head will unify with any DictIn for which
   % select_dict(mydict{key1 : Val1, key2: Val2 }, DictIn, _) succeeds
   % 
  1. To allow for the same kind of notation in goals, like
mypred(SomeVar ) :-
   % The next line is the same as writing:
   % select_dict(mydict{key1 : Val1, key2: Val2 }, SomeVar, _)
   SomeVar = mydict{key1: Val1, key2: Val2, ...};
   % the following line would produce exacly the same select_dict/3 call
   mydict{key1: Val1, key2: Val2, ... } = SomeVar.

It seems to me this solves the major usability frictions that are found with dicts. Any thoughts?

Rather than select_dict/3, you probably want :</2. I.e., one writes

mypred(Dict) :-
    mydict{key1: Val1, key2: Val2} :< Dict,
    ...

vs your proposal

mypred(mydict{key1: Val1, key2: Val2, ...}) :-
     ...

I’m reluctant. Being more compact is of course a good thing. But, what is a dict with , ...? According to how it behaves it should be a dict that, when involved in a unification, performs a partial unification, no? That would require some annotation on the dict and some change to unification to handle such dicts in a special way. For head unification we could of course do something fancy. It gets a bit hard to explain if there is no general principle behind this, especially as long as we have “code is data”. How does this dict behave when involved in comparison, etc.? Picat gave up on code is data, but that is a direction I do not want to go.

3 Likes

I completely agree, having prolog without isomorphism is like having a house without a roof. I would not want that at all. However, I do think there is a possibility of assigning a meaning to the construct that does not affect isomorphism. Have to think more about it.

I have not used dicts and I don’t prefer the , … syntax, but the concept is clearly the same as |_ in [X,Y | _ ]. But do you want to follow the road of open dicts (cf. open lists)? What follows is not the same data structure and semantics as the current fixed dicts.

?-  X = p{a: 2}, X{b} = 3.
X = p{a:2, b:3}.

Think of p{} as an open hash table that in prolog fashion you can add key:_ at any time and this isn’t a setarg but more akin to Tail = [key:_ |Tail2].

X = Y, if both are dicts with the same tag would result in the set union of X’s keys and Y’s keys, and unification of each X and Y value.
X == Y would however demand identical keys.

Given this, you could just write

mypred( mydict{ key1: Val1, key2: Val2} ) :-

and it would accept any mydict{} whether it has key1, key2 or not, or more keys, provided Val1 and Val2 can be unified.

This makes a ton of sense with the way JSON is commonly used with tons of potential keys, many skipped in a data transfer.

HOWEVER: it is very useful to a programmer to have coding mistakes like the following fail, rather than succeed quietly.

X = p{color: 3}, 
Y = p{colour: _Unknown}, 
X = Y.

So I’m not sure I’d want such semantics on =/2.

Aside: There are thousands of times I write code like

% mode +
mypred(X) :-
         X = myterm(Val1, Val2, _, _)

because I want to have a var for both the structure and the contents. Given this, the original syntax question can’t even arise.

They are not. They are implemented as an ordered list of (key,value) pairs represented as an array. In fact, as “Tag, Value1, Key1, Value2, Key2, …” where the Keys are ordered. This allows lookup with log complexity and many of the other operations in linear time. Prolog data does not change, so adding a key creates a new dict.

I know they are not; I was explaining a alternative scenario of having an open hash table, that would make sense of the original post.

My idea was to find a way to provide a way to distinguish between an exact unification (which is the current syntax, the one you showed above) and a partial unification without changing the current meaning.

You are quite right there are some similarities, and it points, I think to the base problem.

I was thinking the base problem, the more fundamental problem, is that for the moment prolog does not have a way to represent a partial group of arguments within a term. In other words, there exists no term which is able to express a group of arguments within a term.

If we are able to solve that, in a consistent and logical manner, it would allow for many possibilities, including the original partial unification of dicts.

Yes, if mydict has 20 keys, it becomes unreasonable to spell out mydict in the argument definition, unless there is a syntax to handle that. An issue with your proposal is that call parameters get =/2 unified to the argument, not partial unification.

For posterity, I just wanted to point to GitHub - edechter/open_dicts: Open dicts for SWI Prolog which does something very similar, instead of ,... it uses + as suffix operator to mark a dictionary as “open” (I think using attributed variable), I think the approach work even in rule heads.