Easier way to get "unique" bindings? - prolog

Sorry if my terminology is off. Long term (40 years? ouch...) imperative programmer, dabbled in functional, spending some time this morning trying to be a bit more serious about declarative. Going through a learning site, and decided to try the "crossword" in exercise 2.4 here: http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse7
I've got it, but it feels ridiculously clunky. Here's my newbie solution:
word(astante, a,s,t,a,n,t,e).
word(astoria, a,s,t,o,r,i,a).
word(baratto, b,a,r,a,t,t,o).
word(cobalto, c,o,b,a,l,t,o).
word(pistola, p,i,s,t,o,l,a).
word(statale, s,t,a,t,a,l,e).
crossword(V1,V2,V3,H1,H2,H3):-
word(V1,V1a,V1b,V1c,V1d,V1e,V1f,V1g),
word(V2,V2a,V2b,V2c,V2d,V2e,V2f,V2g),
word(V3,V3a,V3b,V3c,V3d,V3e,V3f,V3g),
word(H1,H1a,H1b,H1c,H1d,H1e,H1f,H1g),
word(H2,H2a,H2b,H2c,H2d,H2e,H2f,H2g),
word(H3,H3a,H3b,H3c,H3d,H3e,H3f,H3g),
V1b = H1b,
V1d = H2b,
V1f = H3b,
V2b = H1d,
V2d = H2d,
V2f = H3d,
V3b = H1f,
V3d = H2f,
V3f = H3f,
not(V1 = V2),
not(V1 = V3),
not(V1 = H1),
not(V1 = H2),
not(V1 = H3),
not(V2 = V3),
not(V2 = H1),
not(V2 = H2),
not(V2 = H3),
not(V3 = H1),
not(V3 = H2),
not(V3 = H3),
not(H1 = H2),
not(H1 = H3),
not(H2 = H3).
It works. crossword will give me the two possible layouts (puzzle is symmetric, after all). But yeesh...
Some of the clunkiness is just because I've only started, so I don't have any feel for how to mark bindings as "don't care" (the 1st, 3rd, 5th, and 7th letters of the words are completely irrelevant, for instance). But what is really chafing me right now is having to put in the triangular matrix of "don't duplicate any bindings" there at the end. This issue keeps coming up (an earlier toy problem involved loves(A,B) and jealous(X,Y) and if you allow X=Y then everybody leading off a loves relationship is claimed to be jealous of themselves (which I see someone else was fighting with a few years ago:Get unique results with Prolog)), but this tutorial doesn't address it. It hasn't even told me about 'not' yet -- I had to dig around elsewhere to get that, which led into completely valid questions of "well, what kind of 'not equal' did you want?", which I am currently unprepared to answer. But I digress...
It is inconceivable to me that this is the way this actually gets done in real code. Combinatorially, it's ridiculous. And it seems like it violates (or at least bends) the principal of least astonishment. Without the uniqueness restrictions, there are a huge number of solutions that just set V1=H1, V2=H2, V3=H3. I guess I could have only disallowed those, but the real solution needs to do the full restriction.
Yes, I completely understand that logically and mathematically there is no reason not to bind the same value into multiple parameters, and also that there are many situations where such a multiple binding is not just helpful but required to handle the issues at hand. I'm not arguing with the default behavior at all, just looking for a better way to express uniqueness constraints when I need them.
I'd love to know a better way to handle this, because honestly I don't think I can dig much deeper into these tutorials if they're all going to require this much fluff to do something so seemingly obvious.
Thanks in advance!

In my opinion, the exercise is setting you up for failure.
First, because it uses a knowledge representation that is unsuitable for processing similar elements in a uniform fashion.
Second, because you do not have the necessary prerequisites at this point in the book to do so, even if the knowledge representation would make it easier.
I can assure you: What you are doing is of course not necessary when programming in Prolog.
So, don't let a single book detract you from the language.
At this point, I would like to show you how you could solve this task if you had more experience with the language, and used more suitable language features. You may enjoy going back to this later, when you have read other material.
The key change I would like to make is to let you reason about the available words more explicitly, as data structures that are available within your program, instead of "only" as facts:
words(Ws) :-
Ws = [[a,s,t,a,n,t,e],
[a,s,t,o,r,i,a],
[b,a,r,a,t,t,o],
[c,o,b,a,l,t,o],
[p,i,s,t,o,l,a],
[s,t,a,t,a,l,e]].
You can of course easily obtain such an explicit (sometimes called spatial) representation automatically, using all-solutions predicates such as findall/3.
The key predicate I now introduce lets us relate a word in this representation to its every second letter:
word_evens([_,A,_,B,_,C,_], [A,B,C]).
Note how easily this relation can be expressed if you can reason explicitly about the list of letters that constitute a word.
Now, the whole solution, using the predicates permutation/2 and transpose/2, which you can either find as library predicates in your Prolog system, or also implement easily yourself:
solution(Ls) :-
Ls = [V1,V2,V3,H1,H2,H3],
words(Ws),
Ws = [First|_],
maplist(same_length(First), Ls),
maplist(word_evens, [H1,H2,H3], Ess),
transpose(Ess, TEss),
maplist(word_evens, [V1,V2,V3], TEss),
permutation(Ws, Ls).
Sample query and the two solutions:
?- solution(Ls).
Ls = [[a, s, t, a, n, t, e], [c, o, b, a, l, t, o], [p, i, s, t, o, l|...], [a, s, t, o, r|...], [b, a, r, a|...], [s, t, a|...]] ;
Ls = [[a, s, t, o, r, i, a], [b, a, r, a, t, t, o], [s, t, a, t, a, l|...], [a, s, t, a, n|...], [c, o, b, a|...], [p, i, s|...]] ;
false.
At least maplist/2 should be available in your Prolog, and same_length/2 is easy to define if your system does not provide it.
If you really want to express disequality of terms, use prolog-dif.

But what is really chafing me right now is having to put in the triangular matrix of "don't duplicate any bindings" there at the end.
We can get a better solution with the all_dif/1 predicate from here: https://stackoverflow.com/a/47294595/4391743
all_dif([]).
all_dif([E|Es]) :-
maplist(dif(E), Es),
all_dif(Es).
This predicate accepts a list of elements that are all different from each other. Don't worry about not understanding it just yet, you can treat it as a black box for now.
You can use this to replace the big block of not goals at the end of your predicate definition:
crossword(V1,V2,V3,H1,H2,H3):-
... % unchanged code here
all_dif([V1, V2, V3, H1, H2, H3]).
With this you get back to only the two solutions in which all the words are used.
I don't have any feel for how to mark bindings as "don't care" (the 1st, 3rd, 5th, and 7th letters of the words are completely irrelevant, for instance).
This is indeed a very important issue! And Prolog should warn you about variables you only use once (called "singletons"), because they are a frequent source of bugs:
Singleton variables: [V1a,V1c,V1e,V1g,V2a,V2c,V2e,V2g,V3a,V3c,V3e,V3g,H1a,H1c,H1e,H1g,H2a,H2c,H2e,H2g,H3a,H3c,H3e,H3g]
You explicitly mark a variable as "don't care" by giving it a name that starts with the underscore character _, or just naming it _ altogether. Different occurrences of _ mark different "don't care" variables. So we get:
crossword(V1,V2,V3,H1,H2,H3):-
word(V1,_,V1b,_,V1d,_,V1f,_),
word(V2,_,V2b,_,V2d,_,V2f,_),
word(V3,_,V3b,_,V3d,_,V3f,_),
word(H1,_,H1b,_,H1d,_,H1f,_),
word(H2,_,H2b,_,H2d,_,H2f,_),
word(H3,_,H3b,_,H3d,_,H3f,_),
V1b = H1b,
V1d = H2b,
V1f = H3b,
V2b = H1d,
V2d = H2d,
V2f = H3d,
V3b = H1f,
V3d = H2f,
V3f = H3f,
all_dif([V1, V2, V3, H1, H2, H3]).
The warnings are gone and we the program is easier to read because the underscores leave "holes" in uninteresting places, and we see more clearly which variables matter.
That leaves us with the task of removing all those equations. General Prolog tip: Except maybe sometimes for reasons of clarity, there is never any need to write an equation of the form Var1 = Var2 where both sides are variables. Just use the same name for both variables in the whole clause, and you get the same result!
So let's replace V1b and H1b by the same variable named A, V1d and H2b by the same variable B, etc.:
crossword(V1,V2,V3,H1,H2,H3):-
word(V1,_,A,_,B,_,C,_),
word(V2,_,D,_,E,_,F,_),
word(V3,_,G,_,H,_,I,_),
word(H1,_,A,_,D,_,G,_),
word(H2,_,B,_,E,_,H,_),
word(H3,_,C,_,F,_,I,_),
all_dif([V1, V2, V3, H1, H2, H3]).
This is equivalent to your initial solution and, I hope, fairly beginner-friendly.
Hopefully this convices you that Prolog programs can be a bit less clunky than your first attempt. Please stick around, we're here to help if you get stuck, and hopefully you will have some less frustrating experiences and see the magic of Prolog.

Related

Prolog - subsitution and evaluation

Hello good people of programming .
Logic programming is always fascinating compare to imperative programming.
As pursuing unknown of logic programming, there is some problems encountering arithmetic expressions.
Here is the code I have done so far.
number_atom(N) :-
(number(N) -> functor(N, _, _); functor(N, _, _), atom(N)).
arithmeticAdd_expression(V,V,Val,Val).
arithmeticAdd_expression(N, _Var, _Val, N) :-
number_atom(N).
arithmeticAdd_expression(X+Y, Var, Val, R) :-
arithmeticAdd_expression(X, Var, Val, RX),
arithmeticAdd_expression(Y, Var, Val, RY),
(number(RX), number(RY) -> R is RX + RY; R = RX + RY).
Taking add operation as example:
arithmeticAdd_expression(Expression, Variable, Value, Result)
?- arithmeticAdd_expression(a+10, a, 1, Result).
?- Result = 11;
?- Result = a + 10.
?- arithmeticAdd_expression(a+10, b, 1, Result).
?- Result = a + 10.
What I would like to achieve is that
if the atom(s) in the Expression can only be substituted by given Variable and value, then Result is the number only like the example shown above(Result = 11). Else, the Result is the Expression itself only. My problem with the code is somewhere there, I just could figure it out. So, Please someone can help me? Thank you.
An important attraction of logic programming over, say, functional programming is that you can often use the same code in multiple directions.
This means that you can ask not only for a particular result if the inputs are given, but also ask how solutions look like in general.
However, for this to work, you have to put some thought into the way you represent your data. For example, in your case, any term in your expression that is still a logical variable may denote either a given number or an atom that should be interpreted differently than a plain number or an addition of two other terms. This is called a defaulty representation because you have to decide what a variable should denote by default, and there is no way to restrict its meaning to only one of the possible cases.
Therefore, I suggest first of all to change the representation so that you can symbolically distinguish the two cases. For example, to represent expressions in your case, let us adopt the convention that:
atoms are denoted by the wrapper a/1
numbers are denoted by the wrapper n/1.
and as is already the case, (+)/2 shall denote addition of two expressions.
So, a defaulty term like b+10 shall now be written as: a(b)+n(10). Note the use of the wrappers a/1 and n/1 to make clear which case we are dealing with. Such a representation is called clean. The wrappers are arbitrarily (though mnemonically) chosen, and we could have used completely different wrappers such as atom/1 and number/1, or atm/1 and nmb/1. The key property is only that we can now symbolically distinguish different cases by virtue of their outermost functor and arity.
Now the key advantage: Using such a convention, we can write for example: a(X)+n(Y). This is a generalization of the earlier term. However, it carries a lot more information than only X+Y, because in the latter case, we have lost track of what these variables stand for, while in the former case, this distinction is still available.
Now, assuming that this convention is used in expressions, it becomes straight-forward to describe the different cases:
expression_result(n(N), _, _, n(N)).
expression_result(a(A), A, N, n(N)).
expression_result(a(A), Var, _, a(A)) :-
dif(A, Var).
expression_result(X+Y, Var, Val, R) :-
expression_result(X, Var, Val, RX),
expression_result(Y, Var, Val, RY),
addition(RX, RY, R).
addition(n(X), n(Y), n(Z)) :- Z #= X + Y.
addition(a(X), Y, a(X)+Y).
addition(X, a(Y), X+a(Y)).
Note that we can now use pattern matching to distinguish the cases. No more if-then-elses, and no more atom/1 or number/1 tests are necessary.
Your test cases work as expected:
?- expression_result(a(a)+n(10), a, 1, Result).
Result = n(11) ;
false.
?- expression_result(a(a)+n(10), b, 1, Result).
Result = a(a)+n(10) ;
false.
And now the key advantage: With such a pure program (please see logical-purity for more information), we can also ask "What do results look like in general?"
?- expression_result(Expr, Var, N, R).
Expr = R, R = n(_1174) ;
Expr = a(Var),
R = n(N) ;
Expr = R, R = a(_1698),
dif(_1698, Var) ;
Expr = n(_1852)+n(_1856),
R = n(_1896),
_1852+_1856#=_1896 ;
Expr = n(_2090)+a(Var),
R = n(_2134),
_2090+N#=_2134 .
Here, I have used logical variables for all arguments, and I get quite general answers from this program. This is why I have used clpfd constraints for declarative integer arithmetic.
Thus, your immediate issue can be readily solved by using a clean representation, and using the code above.
Only one very small challenge remains: Maybe you actually want to use a defaulty representation such as c+10 (instead of a(c)+n(10)). The task you are then facing is to convert the defaulty representation to a clean one, for example via a predicate defaulty_clean/2. I leave this as an easy exercise. Once you have a clean representation, you can use the code above without changes.

How to attach properties to terms?

I want to attach properties to my terms, from a set of about 50 different properties. Usually only a small subset of them are used for a given term. There are many ways to represent these properties, but I am not satisfied with any of them.
For the sake of discussion, here is a set of properties and their possible values:
hair: bald, blonde, brune, red
eyes: blue, green, brown
first_name: John, Dick, Harry
There are many ways to represent these properties, for example with a list of pairs:
[eyes-blue, hair-blonde]
The only representation that seems to work is to use a very long list, where each index is used for a specific property:
?- T1=[blonde,_,_], T2=[_,blue,_], T1=T2.
T1 = T2, T2 = [blonde, blue, _1266]
?- T1=[X,_,_], X=blue.
T1 = [blue, _1230, _1236],
X = blue
But it's unreadable with 50 properties, and very bugprone (in my case, a whole set of predicates is dedicated to each property, and sometimes to each value of a property).
The way I would use such a feature would be by having conditions like "Terms T1 and T2 have the same value for property X", or "Terms T1 and T2 are the same", where T1 and T2 have attributes which can be set elsewhere, or can be left unset.
Using dicts desn't work, because unset keys are considered non-existent:
?- T1 = _{eyes:blue, hair:blonde}, T2 = _{eyes:blue}, T1 = T2.
false.
For this to work, I would need to initialize each term with the 50 (mostly irrelevant) properties with free variables, on the off-chance that some of them will be used.
What other options do I have? I am open to using a different logic programming language if there is something closer to my needs than prolog.
With the "very long list", you have indeed found one possible representation that lets you directly use Prolog's built-in unification to perform the task for you.
As you note, this comes at a price though: It's unreadable, error-prone, wasteful etc.
There are many possible ways to solve the task, and I would like to give you two pointers that I hope you find relevant for your task.
Option 1: Use lists of pairs
This is in fact already mentioned in your post. Pairs of the form hair-blonde etc. are a natural way to represent the available data. By convention, (-)/2 is frequently used to denote pairs in Prolog.
All that is missing is precisely describing what "merging" such pairs means. You call it "unification", so let us use this terminology although it is of course different from syntactic unification that is available with (=)/2. One way to define the relation we want is:
unify_pairs([], APs, APs).
unify_pairs([A1-P1|APs1], APs2, APs) :-
if_(selectd_t(A1-P1, APs2, APs2Rest),
APs=[A1-P1|Rest],
if_(attr_exists_t(A1, APs2),
false,
APs = [A1-P1|Rest])),
unify_pairs(APs1, APs2Rest, Rest).
attr_exists_t(A, APs, T) :-
pairs_keys(APs, As),
memberd_t(A, As, T).
selectd_t(E, Xs0, Xs, T) :-
i_selectd_t(Xs0, Xs, E, T).
i_selectd_t([], [], _, false).
i_selectd_t([X|Xs], Rest, E, T) :-
if_(X=E, (T=true,Rest=Xs), (Rest = [X|Rs],i_selectd_t(Xs, Rs, E, T))).
This uses library(reif) and two auxiliary predicates to distinguish the different cases.
Your test cases work as required. For example:
?- unify_pairs([hair-blonde], [eyes-blue], Ps).
Ps = [hair-blonde, eyes-blue].
?- unify_pairs([eyes-blue], [eyes-brown], Ps).
false.
Importantly, we can use it in all directions, and so we can also post significantly more general queries. For example:
?- unify_pairs([T1-P1], [T2-P2], TPs).
T1 = T2,
P1 = P2,
TPs = [T2-P2] ;
TPs = [T1-P1, T2-P2],
dif(T2, T1),
dif(f(T2, P2), f(T1, P1)).
Such answers help us to obtain a better understanding of the relation, and to test it more exhaustively.
Option 2: Use lists of pairs again
The second pointer I would like to include is found in library(ordsets) and similar libraries that ship with several Prolog systems.
This again lets you use lists, even lists of pairs. Importantly, lists are available in all Prolog systems. Various operations are quite efficient due to the way these libraries represent sets as ordered lists.
However, the price you may pay in such cases is the generality explained in the first approach. I suggest you first try the more general approach (i.e., Option 1), and then, only if necessary, resort to lower-level approaches that are more error-prone and less general.
You maybe say "unification" but you mean something different from what unification normally means in Prolog which is why your question might be mistaken for a different question. You could do some things with SWI-Prolog dicts:
?- _{hair:blonde, eyes:blue} >:< _{eyes:blue}.
true.
?- _{hair:blonde, eyes:blue} >:< _{eyes:blue, hair:Color}.
Color = blonde.
?- _{hair:blonde, eyes:blue} >:< _{eyes:blue, hair:bald}.
false.
but you cannot directly do what you need, because if you "put" into a dict you add or replace which is not what you want.
?- R =_{eyes:blue}.put(_{hair:blonde}).
R = _7436{eyes:blue, hair:blonde}.
(this one was OK)
?- R =_{eyes:blue}.put(_{eyes:brown}).
R = _7436{eyes:brown}.
(this is not what you want, is it?)
what you want I don't know what to call in words but it is some form of finding union on keys in key-value pairs. But you can just do it with dicts I think if you first do P1 >:< P2 and then put_dict(P1, P2, Result)?
?- P1 = _{eyes:blue},
P2 = _{hair:blonde,eyes:brown},
P1 >:< P2, put_dict(P1, P2, Result).
false.
?- P1 = _{eyes:blue},
P2 = _{hair:blonde},
P1 >:< P2, put_dict(P1, P2, Result).
Result = _10044{eyes:blue, hair:blonde}.
?- P1 = _{eyes:blue},
P2 = _{hair:blonde,eyes:blue},
P1 >:< P2, put_dict(P1, P2, Result).
Result = _10046{eyes:blue, hair:blonde}.
Please respond if this is what you were asking because I am really not sure? But what is even more important actually is that you think a bit more carefully about the real problem you are trying to model because maybe? (just maybe?) you are thinking of it in terms of solution that is not as good as another solution that will make the problem be a lesser problem or a problem with already existing better solutions. Maybe it will help if you provide even more context about your problem in your question, because now there is enough context about how you tried to solve it but I don't know what you are really solving.
You could make the attributes one-arity terms, like this:
hair(bald)
hair(blonde)
eyes(blue)
eyes(green)
...
That would rule out unifications like
hair(blonde) = hair(red)
and you could quite easily write your own predicate for combining two lists, which could also block/filter out multiple instances of the same attribute.
In languages with strong typing this is a nice representation, but I'm not sure it's so useful in Prolog. Anyway it is a possibility.
I think I understand your question but I don't think I understand your difficulty. You could achieve what you want with dicts, with assocs, with lists of pairs.... You say:
Terms T1 and T2 have the same value for property X
Here it is with dicts, like the answer by #User9213:
?- _{a:1, foo:2, bar:3}.a = _{a:2, foo:22, baz:33}.a.
false.
?- _{a:1, foo:2, bar:3}.a = _{a:1, foo:22, baz:33}.a.
true.
In other words, to compare a "property" of two dicts, you just say Dict1.X = Dict2.X. Note that this also works with X a variable:
?- X = a, _{a:1, b:2}.X = _{a:1, b:432432}.X.
X = a.
The same would work with any other option already mentioned: with library(assoc) (just get the values for that key and compare), or even for lists of pairs (just do member(Key-Value, List) and compare values).
Then, you also say,
Terms T1 and T2 are the same
Now you really can just compare dicts. For assocs, I am not certain if two assocs are always the same if they have the same contents, but you can make lists and compare those. And if you keep your lists of pairs sorted on keys, you can just compare, as with dicts.
Finally, you say:
where T1 and T2 have attributes which can be set elsewhere, or can be left unset.
This is ambiguous. If an attribute is unset, just leave it out of the dict/assoc/list. "Set elsewhere" I really don't get.
You need to write some code down and get a feel for how things could be done. Showing your difficulties with a code example will help you get specific and useful answers.

What does member[H|T] mean?

I am just learning Prolog and stumbled across following question: Prolog - Seeing if the same element occurs in two lists.
This question includes following line: =(member(X,[H|T]), member[Z|Q])).
I know about member(?Elem, ?List), but I do not understand the member[Z|Q] part. What does this mean? And isn't there a closing paranthesis too much?
Summary:
Do not worry about this at all.
Here are several reasons:
Syntax error
First of all, this is invalid syntax. When you consult the program you link to, you get:
ERROR: file.pl:5:28: Syntax error: Operator expected
indicating exactly the line containing:
=(member(X,[H|T]), member[Z|Q])),
Dubious meaning
Second, even if we somehow fix the problematic syntax, and write this line for example as:
=(member(X,[H|T]), member_whatever),
Then it would still be highly dubious that this is what the author meant to express.
The predicate that is used in this case is (=)/2, and you can write this equivalently using infix notation as:
member(X,[H|T]) = member_whatever,
And from this, it is already clear that this cannot succeed because (=)/2 does not even hold for the much more general case
member(_,_) = member_whatever,
So, it definitely fails of course also in the more specific case above!
Fundamental issues
When programming in Prolog, focus on a clear description of what holds.
For example, to state that "the same elements occurs in two lists" is straight-forward:
element_in_both(E, As, Bs) :-
member(E, As),
member(E, Bs).
That's it! You can read it as follows: If E is a member of As and E is a member of Bs then E is a member of both As and Bs.
It works quite generally, for example:
?- length(Cs, _),
append(As, Bs, Cs),
element_in_both(E, As, Bs).
Cs = [E, E],
As = Bs, Bs = [E] ;
Cs = [E, E, _2946],
As = [E],
Bs = [E, _2946] ;
Cs = [E, _2940, E],
As = [E],
Bs = [_2940, E] .
You can use this predicate to generate lists where this relation holds, to test whether it holds for a specific instance, to complete partial lists such that they satisfy this predicate etc.
All of this follows from a clear declarative description of the conditions that make this relation hold.
In Prolog courses, there is a tendency to needlessly complicate this rather simple fundamental principle of declarative programming. Do not fall into this trap. If your predicate becomes convoluted, your are often overlooking something simpler.

Partial Dictionary/Record Unification?

I understand that some Prologs support dictionary-like associative data structures out of the box. For the implementations that do, do they support some notion of partial unification with another structure that doesn't actually contain all of the keys?
For example, in the syntax of core.logic/miniKanren:
(run* [q]
(== {:foo 1 :bar 2} (partial-map :foo q)))
This would return a single result where q is bound to 1.
Do Prologs give this operation or this partial structure a name?
In general one works around the poor selection of fundamental data types in Prolog the standard way: by adding libraries and using interfaces. SWI-Prolog, for example, comes with the assoc library that implements an AVL tree-based association data structure. (As an aside, balanced trees are more common in functional and logic programming than hash tables because it's easier to create "persistent" data structures on trees than hash tables—persistent in the FP sense of sharing internal structure.)
Using this library looks something like this:
?- [library(assoc)].
% library(assoc) compiled into assoc 0.00 sec, 97 clauses
true.
?- empty_assoc(Assoc).
Assoc = t.
?- empty_assoc(Assoc), get_assoc(test, Assoc, V).
false.
?- empty_assoc(Assoc), put_assoc(test, Assoc, foo, Assoc2).
Assoc = t,
Assoc2 = t(test, foo, -, t, t).
?- empty_assoc(Assoc),
put_assoc(test, Assoc, foo, Assoc2),
get_assoc(test, Assoc2, Value).
Assoc = t,
Assoc2 = t(test, foo, -, t, t),
Value = foo.
Once you have something that gives you an interface like this, you can define all kinds of logical relations on top of it. Once you have logical relations, Prolog's normal unification machinery will take care of the rest—no special support for this or that data type is required. Based on your requirements, I think what you want is like a subset relation, except checking both that all of one association are in the other and they all have the same value. I guess that would look something like this:
association_subset(Left, Right) :-
forall(gen_assoc(Assoc, Left, Value), get_assoc(Assoc, Right, Value)).
This predicate will only be true if the Left association is a subset of the Right association, as defined above. We can test it and see if it's doing what we want:
simple(Assoc) :-
empty_assoc(Empty),
put_assoc(foo, Empty, foo_test, V1),
put_assoc(bar, V1, bar_test, Assoc).
complex(Assoc) :-
simple(Assoc1),
put_assoc(baz, Assoc1, bazzle, Assoc).
unrelated(Assoc) :-
empty_assoc(Empty),
put_assoc(baz, Empty, bazzle, Assoc).
...
?- simple(X), complex(Y), association_subset(X, Y).
X = t(foo, foo_test, <, t(bar, bar_test, -, t, t), t),
Y = t(baz, bazzle, -, t(bar, bar_test, -, t, t), t(foo, foo_test, -, t, t)).
?- simple(X), simple(Y), association_subset(X, Y).
X = Y, Y = t(foo, foo_test, <, t(bar, bar_test, -, t, t), t).
?- simple(X), unrelated(Y), association_subset(X, Y).
false.
?- complex(X), simple(Y), association_subset(X, Y).
false.
We can translate this to your exact question like so:
left(Assoc) :-
empty_assoc(Empty),
put_assoc(foo, Empty, 1, Assoc).
right(Assoc) :-
left(Assoc1),
put_assoc(bar, Assoc1, 2, Assoc).
?- left(L), right(R), association_subset(L, R), get_assoc(foo, L, Q).
L = t(foo, 1, -, t, t),
R = t(foo, 1, <, t(bar, 2, -, t, t), t),
Q = 1.
I realize that this answer doesn't really answer the question you asked, but I hope it answers the question beneath the question. In other words, there doesn't need to be special support for these data structures—the above predicate could be defined over association lists as well, you can see that all you'd need is the usual ways of making empty associations, adding, testing for, and generating the keys/values of the association and the underlying data structure becomes irrelevant. No special support is necessary either data-structure-wise or unification-wise. Special syntax would certainly make it nicer to look at! But it isn't necessary to get the behavior you desire.
Some Prolog systems such as Eclipse have a record notation. This can be used
when you know in advance the possible keys of your map. But it needs
a type declaration. The record notation is also found in Prolog decendant
languages such as Erlang.
The idea is very simple. You first declare
a record type (some syntax invented here):
:- rectype T{K1,...,Kn}.
Now you can use inside your Prolog program
records, just write (again some syntax invented here):
... T{F1 = V1, .., Fn = Vm} ...
At compile type the record will be converted into a compound
and can then easily be used in normal unification. The conversion
reorders the key value pairs according to the record type
declaration, then drops the keys and uses the positions only.
Unused positions are replaced by annonymous variables or
by default values if the record type declaration also
covers this.
... T(W1, ..., Wn) ...
Your example would work as follows:
:- rectype myrec{foo, bar}
?- myrec{foo=1,bar=2} = myrec{foo=q}
The latter query would be internally executed as:
?- myrec(1,2) = myrec(q,_).
For more details how Eclipse does it, see for example here:
http://www.eclipseclp.org/doc/bips/kernel/syntax/struct-1.html
For dynamic maps where the keyset is not static you can implement
dynamic data structures as the other post about SWI-Prolog AVL
trees shows. Or ask your Prolog system for a handle to a specific
data structure. Implement these with a FFI (Foreign Function Interface)
or access these which are already bundled with the Prolog system.
Eclipse for example bundles a couple, see "Description" section
in the below article:
http://www.eclipseclp.org/doc/bips/kernel/record/index.html
Bye
It is not that clear to me what you actually want, (you have removed the hashing aspect), but maybe you rather want feature terms or feature structures?
They are popular to linguists and have been part of Life.
It is possible to implement them with the help of attributed variables, but so far, I have not seen much of a demand for them.
You can also simulate them a bit clumsily with syntactic unification. It is clumsy because you need to represent each feature with a separate argument (you can do this slightly better, but it is also more complex then). So if your program contains n features, a feature structure will contain n different arguments most of which will never be touched. However, unification will then work directly as intended.

PROLOG -- logic base of entries to LIST of entries

In PROLOG I have a logic base of entries (which are stored in memory) which I have to convert to a list of entries.
example:
| ?- rule(A,B).
A = member(_h209,[_h209|_h212])
B = true;
A = member(_h209,[_h211|_h212])
B = member(_h209,_h212);
TO
[member(_h209,[_h209|_h212]),true,member(_h209,[_h211|_h212]),member(_h209,_h212);]
Can anyone please let me know how can I get it.
something close to your expected result (except the semicolon at end) could be:
rule_list(Rules) :-
findall([A, B], rule(A, B), L),
flatten(L, Rules).
A note on _h209, occurring at first position of member: I'm not sure you know the meaning of such symbols. These are variables, and if you interested in mantaining the identities these express, my suggestion isn't correct. Use bagof in such case.

Resources