🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.prolog
Article #1686

Re: Abstract Type in Prolog ?

#1686
From: Mark Lutz
Date: Fri, 04 Jan 1991 00:01
133 lines
4775 bytes
in article 2819 of comp.lang.prolog, yfeng@watnow.waterloo.edu writes:
> I am wondering if prolog can be used to represent abstract data type.
> For example: an axiomatic specification of stack is something like:
>
> top(push(i,s)) = i
> isemptystack(createstack) = true
> isemptystack(push(i,s)) = false
> pop(push(i,s)) = s
>
> Can this set of axioms be represented in prolog directly ?


I dont know if this answers your question, but it is trivial to
code these in prolog--just make the output an extra argument,
assert predicates you want to return 'true', and omit those you 
want to return 'false' so they fail and invoke backtracking;  
for example, your: 

    top(push(i,s)) = i
    isemptystack(createstack) = true
    isemptystack(push(i,s)) = false
    pop(push(i,s)) = s

becomes:

    top(push(I,S),I).
    is_empty_stack(createstack).
    pop(push(I,S),S).

and presumably, you need to have:

    push(I,S,push(I,S)).
    new_stack(createstack).

push() takes a node I, a stack S, and outputs a new stack
in the third argument;  'push(_,_)' is essentially like a 
lisp cons cell here--the 'stack' is really a binary tree
of push(_,_) nodes that grows through its right branches.
A more common way to implement stacks is with prolog lists:

    new_stack([]).
    push(X,S,[X|S]).
    pop([X|S],S).
    etc. 

but this is really no different than using a push(_,_) tree,
since prolog lists are .(_,_) trees internally (usually).

Now, a prolog program can load these predicates, and create 
and manipulate arbitrarily many stacks, without ever needing
to know the actual data structures that implement the stack,
so long as all updates are done with the provided predicates:

some_program :-
    new_stack(S),
    push(term1,S,S1),
    push(term2,S1,S2),
    pop(S2,S3),
    push(term3,S3,S4),
    top(S4,term3),
      /* here, S4 = push(term3,push(term1,createstack)) */ 

    new_stack(T),
    push(term1,T,T1),
    pop(T1,T2),
    is_empty_stack(T2),...
      /* here, T2 = createstack, i.e. empty */

Note, however, that such a stack must be passed around as an
argument to all routines that use it, each change to a stack 
requires a new variable to be bound to the modified stack, 
and changes to such stacks will be undone when backtracking 
past the point in the computation where the modification was 
made;  if you want globally accessible stacks, insulated from 
the effects of backtracking, you need to use assert/retract, 
or some similar facility in your prolog system (never really 
a good idea).


Incidentally, prolog is really very good at abstract data types
in general;  for example, you could switch the stack representation
from 'push(_,_)' to '[_|_]' arbitrarily, and could even change the 
shape of the stack 'tree' to grow to the left without altering
the calling programs:

    top(push(S,I),I).
    push(I,S,push(S,I)).
    pop(push(S,I),S).
    etc.

some_program :-
    new_stack(S),
    push(term1,S,S1),
    push(term2,S1,S2),
    pop(S2,S3),
    push(term3,S3,S4),
    top(S4,term3),
      /* here, S4 = push(push(createstack,term1),term3) */ 


As another example, one could define a simple:

    new_dict([]).

    store(Key,Value,Dict,[(Key,Value)|Dict]).

    lookup(Key,Value,Dict) :- member((Key,Value),Dict).

to implement a dictionary with linear lists, and later change 
this to use a very different binary tree representation, without 
impacting any using programs, provided they only access the 
dictionary with the new_dict(), store() and lookup() predicates:

    new_dict(nil).

    store(K,V,nil,tree(nil,(K,V),nil)).
    store(K,V,tree(L,(X,Y),R),tree(L2,(X,Y),R)) :- K < X, store(K,V,L,L2).
    store(K,V,tree(L,(X,Y),R),tree(L,(X,Y),R2)) :- K > X, store(K,V,R,R2).

    lookup(K,V,tree(L,(K,V),R)).
    lookup(K,V,tree(L,(X,Y),R)) :-  K < X, lookup(K,V,L).
    lookup(K,V,tree(L,(X,Y),R)) :-  K > X, lookup(K,V,R).

If one were truly ambitious, they could even use a module facility
to keep everything except the interface predicates hidden from the using 
program (provided their prolog system provides modules).


Hope this helps,

Mark Lutz
mlutz@convex.com
Technical Details
Message-ID: <1991Jan04.000100.10872@convex.com>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!convex!news
References: <1991Jan3.154717.27057@watserv1.waterloo.edu>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!convex!news
From: mlutz@convex.COM (Mark Lutz)
Newsgroups: comp.lang.prolog
Subject: Re: Abstract Type in Prolog ?
Message-ID: <1991Jan04.000100.10872@convex.com>
Date: 4 Jan 91 00:01:00 GMT
References: <1991Jan3.154717.27057@watserv1.waterloo.edu>
Sender: news@convex.com (news access account)
Reply-To: mlutz@convex.COM (Mark Lutz)
Organization: Convex Computer Corporation; Richardson, TX
Lines: 133
Nntp-Posting-Host: mozart.convex.com