Is it possible to write an empty list as a difference list in Prolog?

冷暖自知 提交于 2019-12-10 20:49:33

问题


Empty lists are ... strange, to a Prolog beginner like myself. I would say that it isn't possible to write an empty list [] as a difference list T1-T2 just as it isn't possible to write an atom as a difference list. However, I would guess that to use recursion, there must be a way to use [] in a difference list setting. I have Google'd for this but I cannot find an answer, and Bratko (Prolog Programming for AI) only briefly touches the subject.

So, is it possible to write an empty list as a difference list in Prolog, if so how and when would it be useful?


回答1:


Problems with understanding this topic are typically due to using misleading terminology.

As recommended in tutorial.pdf and especially pap95.pdf, use for example list difference or simply difference.

Section 5 of Teaching beginners Prolog contains relevant reasons for this.

The empty list is uniquely denoted by the atom [].

Note that a list difference always means reasoning about two lists, and due to this categorical difference between a single and multiple lists, you can at best find some correspondence or analogy, but not identity between the empty list and a list difference.

I completely support the view expressed in the paper above that you should focus on using DCGs, at least at first. Reasoning about differences explicitly will come naturally later to you.




回答2:


Appending two list differences means just a unification of first diff's end pointer with the second one's head. With regular lists it requires retracing of the whole list structure of the first list. Thus repeated concatenation on the right is linear with the list difference technique, and quadratic with plain lists.

When all the intended concatenations are done, to return the whole structure as a plain list to a caller we just unify the "end pointer" logvar with [].

In C terms, list difference is a portion of singly-linked list where we maintain two variables: its head pointer but also its tail pointer:

// typedef struct { int payload; node* next } node;
typedef struct { node** head; node** tail } list_diff;

Now each concatenation is just an assignment of the end pointer:

void diff_concat( list_diff* a, list_diff* b)
{
    *(a -> tail) -> next = *(b -> head);
    a -> tail = b -> tail;
}

And finalization is

void diff_finalize( list_diff* a)
{
    *(a -> tail) = NULL;  // or some sentinel value, whatever
}

In Prolog we could represent it as a binary term like -/2, e.g. -(A,B) or A-B.

But (as in C also) there's no actual need to build an actual structure in memory just for holding the two pointers; we can just maintain two logvars individually. Or let DCGs do it for us.

The above was the motivational introduction to list difference technique, "what are they good for?". It also makes clear that the representation of empty difference is

list_diff* d;
*(d -> head) = *(d -> tail);

Or in Prolog, a pair of logvars unified with each other: L-L, var(L). To see why, see what happens when empty diff is appended with some other diff on its right (it is always on the right that we append things, thus growing the lists in the top-down manner). My C may be off here, the idea being that by setting the tail the appending to an empty diff will also update its head.



来源:https://stackoverflow.com/questions/41591498/is-it-possible-to-write-an-empty-list-as-a-difference-list-in-prolog

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!