All data types are inherently abstract.
A data type is defined by giving an algebraic description of the properties of its operators.
E.g., natural numbers could be defined by:
sum( succ( X ), Y, succ( Z )) :- sum( X, Y, Z ). sum( 0, X, X ). ?- sum( succ( succ(0)), succ( succ( succ(0))), Answer ). Answer = succ( succ( succ( succ( succ(0)))))
Due to the inefficiency of this approach, most (all?) versions of Prolog provide basic arithmetic predicates, functions, and operators.
Prolog provides no data constructors.
Prolog can operate directly with a logical description of the properties of a data structure.
Compound terms can represent data structures.
E.g., lists may be represented by the expressions that construct them:
list( nil ).
list( cons( X, L )) :- list( L ).
null( nil ).
car( cons( X, L ), X ).
cdr( cons( X, L ), L ).
?- car( cons( cons( a, cons( b, nil )),
cons( c, cons( d, nil )) ), L ).
L = cons( a, cons( b, nil ))
Prolog provides a built-in operator and some syntactic simplifications for representing lists.
The dot functor or dot operator represents cons.
E.g.,
?- car(( a.b.nil ).( c.d.nil ), X ) X = a.b.nil
If your version of Prolog does not support '.' (dot) as an operator, you can either use it as a functor (in which case the list a.b.nil would be written as .(a, .(b, nil))) or define it as an operator by entering op(51, xfy, '.')..
[] represents nil.
E.g.,
?- car(( a.b.[] ).( c.d.[] ), X ) X = a.b.[]
Prolog does not support nil as an alias for [] -- we introduced its use in the list-related predicates above in order to show the relationship between Prolog lists and LISP lists.
Like LISP, Prolog allows a simpler list notation.
E.g.,
?- car( [[ a, b ], c, d ], X ) X = [a, b]
This is syntactic sugar -- lists are still compound terms.
To simplify splitting a list, Prolog uses [ X | Y ] to represent
a list with head X and tail Y.
E.g.,
member( Element, [ Element | _ ] ). member( Element, [ _ | Tail ] ) :- member( Element, Tail ). ?- member( a, [ a, b, c ] ). yes ?- member( a, [ b, a, c ] ). yes ?- member( d, [ c, b, a ] ). no
[ ] does not match either [ Element | _ ] or [ _ | Tail ].
Strings are represented internally as lists.
A string is another form of list notation.
E.g., "abc" is treated internally as a list of ASCII character codes:
[97, 98, 99]
Example of a user-defined data type: set.
set membership -- same as list membership (see above)
subset
subset( [ A | X ], Y ) :- member( A, Y ), subset( X, Y ). subset( [ ], Y ). % The empty set is a subset of every set.
intersection
% Assumes lists contain no duplicate elements.
intersection( [ ], X, [ ] ).
intersection( [ X | R ], Y, [ X | Z ] ) :-
member( X, Y ),
!,
intersection( R, Y, Z ).
intersection( [ X | R ], Y, Z ) :- intersection( R, Y, Z ).
union
union( [ ], X, X ).
union( [ X | R ], Y, Z ) :-
member( X, Y ),
!,
union( R, Y, Z ).
union( [ X | R ], Y, [ X | Z ] ) :- union( R, Y, Z ).