# Term structure conversions

?Struct =.. ?List

This predicate is referred to as “univ”. Through unification, a correspondence is created between Struct and List where the first element of List is the functor of Struct and each subsequent element of List is unified with each of the arguments of Struct, in order.

For example, the following converts a structure to a list:

tree(oak, seed(acorn)) =.. X.
X = [tree, oak, seed(acorn)]
yes

To convert a list to a structure:

?- X =.. [tree, oak, seed(acorn)].
X = tree(oak, seed(acorn))
yes

Univ can be useful, for instance, when adding new arguments to a structure. These new arguments can be added to the structure by a predicate such as addargs/3, defined below. **addargs/3** uses univ to convert the structure to a list. It then appends the extra arguments to the list. Univ is used a second time to convert the new list back to a structure.

add_args(Struct, ArgList, NewStruct) :-
Struct =.. List,
append(List, ArgList, NewList),
NewStruct =.. NewList.

append([], L, L) :- !.
append([H|T], L, [H|T1]) :-
append(T,L,T1).

You could use add_args/3 to add a third argument to a book structure, as shown:

?- add_args(book(pooh, milne), ['a.a.'], X).
X = book(pooh, milne, 'a.a.')
yes

functor(?Struct, ?Name, ?Arity)

The functor/3 predicate unifies the name of Struct with Name and the number of arguments of Struct (the “arity”) with Arity. Either Struct must be instantiated at call time or both Name and Arity must be instantiated. If Struct is atomic, then Struct is unified with Name and Arity is unified with 0.

For example, functor/3 can be used to identify the Name and Arity of a term as shown:

?- functor((book(pooh, milne, 'a.a.')), X, A).
X = book
A = 3
yes

If the Struct argument is uninstantiated, the functor predicate creates a structure having the specified Name and Arity (maximum 255). The structures arguments are all distinct, uninstantiated variables.

arg(+N, +Term, -Value)

arg0(+N, +Term, -Value)

The arg/3 and arg0/3 predicates unify the value of one argument of Term with Value. The argument is specified by the integer N where arguments are numbered upward from 1 for arg/3 and upward from 0 for arg0/3.

For example, to return the first argument of a book structure, you call arg/3 as follows:

?- arg(1, book(poetry,milne), X).
X = poetry
Yes

You can use arg/3 and arg0/3 to instantiate the variables in a structure. Consider the partial implementation of the univ predicate, defined below. This version of '=..'/2 uses functor/3 and arg/3 to convert a list to a structure. The predicate calls functor to create a structure using the head of the list as the functor. The arguments to this structure, however, are left uninstantiated by functor. The generate predicate is used to instantiate those variables. Each time generate is called, it uses arg to instantiate the next member of the list.

my_univ(Struct, [H|T])  :-
length(T, N),
functor(Struct, H, N),
generate(Struct, 1, T).

generate(S, _, [])  :-  !.
generate(S, N, [H|T])  :-
arg(N, S, H),
inc(N, N1),
generate(S, N1, T).

To convert a list to a structure, you can call univ like this:

?- my_univ(S, [book, pooh, milne]).
S = book(pooh, milne)
yes

Note that this univ predicate only converts a list to a structure. You cannot use it to convert a structure to a list.

argrep(+Struct, +N, +Arg, -Newstruct)

The argrep/3 predicate unifies Newstruct with a term that is equivalent to Struct with the Nth argument replaced by Arg.

For example, if you have the term student(alan,soph,95) and you want to replace the argument 95 with the argument 88:

?- argrep(student(alan,soph,95), 3, 88, X).
X = student(alan,soph,88)
yes

## Arity/Prolog32 term concatenation

term_concat(+Functor, +Args, -Term)

The term_concat/3 predicate can be used to create a new structure from existing ones. Args is a list of terms whose arguments will be copied in order into the new Term. The specified Functor will be used for the new Term.

For example, the following query creates a new structure from three existing ones:

?-term_concat(
record,
[ employee('Smith','Ted'),
division(engineering,'r&d'),
firm('ABC Corp.')
], X).
X = record('Smith','Ted',engineering, 'r&d','ABC Corp.')
yes

In addition, you can specify that only certain arguments of a term may be copied into a new term. The following two special terms can be specified as members of the Args list:

'.'(Term,Start,Stop)
':'(Term,Start,N)

The dot (.) functor specifies that only the arguments of Term between Start and Stop will be copied to the new term. Note: Start and Stop must be integers where Start is less than or equal to Stop.

The colon (:) functor specifies that N arguments of Term beginning at argument Start should be copied to the new term.

The following is an example use of these terms:

?-term_concat(new,
[ x(a,b,c),
':'(y(1,2,3,4,5),2,3),
'.'(z(x(1),x(2),x(3),x(4),x(5)), 3, 4)
], X).
X = new(a,b,c,2,3,4,x(3),x(4))
yes

## Encoding and decoding Arity/Prolog32 terms

Five predicates are provided by Arity/Prolog32 for the encoding and decoding of Prolog terms using the same mechanism as is used for the internal database. The predicates are defined below.

dbsLen(+Term, -/+Len)

Returns the byte length of the string that would be created using term2dbs/2 or term2dbcs/4. This predicate is provided as a convenient way of determining length of the encoded term more efficiently than actually creating it in advance. This is typically used to find out what size buffer is needed for using term2dbcs/4.

term2dbs(+Term, -/+DBString)

This predicate encodes Term as the Prolog string DBString. Term may be unbound.

term2dbcs(+Term, +Ptr, +MaxLen, -/+ActLen)

This predicate encodes Term as a C string at Ptr. If the length of the encoded string is larger than MaxLen then the predicate fails doing no work. The actual length written is returned in ActLen. Note that the string that is created is not null terminated and may contain embedded nulls.

dbs2term(+DBString, -/+Term)

This predicate decodes the Prolog string DBString as Term.

dbcs2term(+Ptr, -/+Term)

This predicate decodes the C string at Ptr as Term. You must ensure that you do not accidently overrun the buffer size.