How to use difference lists in a Prolog interpreter

前端 未结 1 1905
無奈伤痛
無奈伤痛 2021-01-16 09:40

When I was writing down this question on an empty list as a difference list I wanted to test what I knew about those structures. However, when I tried something as simple as

相关标签:
1条回答
  • I think you have the idea that the Prolog interpreter treats difference lists as something special. That is not the case: Prolog is not aware of the concept of a difference list (nor of nearly every concept except some syntactical sugar). He only sees:

    L=-( |(a, |(b, |(c, |(d, |(e, []))))), |(d, |(e, [] )))
    

    where -/2 and |/2 are functors, and a, b, c, d, e and [] are constants.

    Difference lists are simply a programming technique (like for instance dynamic programming is a technique as well, the compiler cannot detect nor treat dynamic programming programs differently). It is used to efficiently unify a (partially) ununified part deep in an expression.

    Say you want to append/3 two lists. You can do this as follows:

    %append(A,B,C).
    append([],L,L).
    append([H|T],L,[H|B]) :-
        append(T,L,B).
    

    But this runs in O(n): you first need to iterate through the entire first list. If that list contains thousands of elements, it will take a lot of time.

    Now you can define yourself a contract that you will feed an append_diff/3 not only the list, but a tuple -(List,Tail) where List is a reference to the beginning of the list, and Tail is a reference to the end of the not unified list. Examples of structures that fulfill this requirement are Tail-Tail, [a|Tail]-Tail, [1,4,2,5|Tail]-Tail.

    Now you can effectively append_diff/3 in O(1) with:

    append_diff(H1-T1,T1-T2,H1-T2).
    

    Why? Because you unify the ununified tail of the first list with the second list. Now the ununified tail of the second lists becomes the tail of the final list. So take for instance:

    append_diff([a|T1]-T1,[1,4,2,5|T2]-T2,L).
    

    If you call the predicate, as you see above, T1 will unify with [1,4,2,5|T2], so now the first list collapses to [a|[1,4,2,5|T2]] or shorter [a,1,4,2,5|T2], since we also have a reference to T2, we can "return" (in Prolog nothing is returned), [a,1,4,2,5|T2]-T2: a new difference list with an open tail T2. But this is only because you give - a special meaning yourself: for Prolog - is simply -, it is not minus, it does not calculate a difference, etc. Prolog does not attach semantics to functors. If you would have used + instead of -, that would not have made the slightest difference.

    So to return back to your question: you simply state to Prolog that L = -([a,b,c,d,e],[d,e]) and later state that L = [a,b,c]. Now it is clear that those two expressions cannot be unified. So Prolog says false.

    0 讨论(0)
提交回复
热议问题