5.2.4 Adapting code for double quoted strings
We observe that in many programs, most strings are only handled as a single unit during their lifetime. Examining real code tells us that double quoted strings typically appear in one of the following roles:
- A DCG literal
- Although represented as a list of codes is the correct representation for handling in DCGs, the DCG translator can recognise the literal and convert it to the proper representation. Such code need not be modified.
- A format string
- This is a typical example of text that is conceptually not a program identifier. Format is designed to deal with alternative representations of the format string. Such code need not be modified.
- Getting a character code
- The construct
[X] = "a"
is a commonly used template for getting the character code of the letter’a'. ISO Prolog defines the syntax0'a
for this purpose. Code using this must be modified. The modified code will run on any ISO compliant Prolog Processor. - As argument to list predicates to operate on strings
- Here, we might see code similar to
append("name:", Rest, Codes)
. Such code needs to be modified. In this particular example, the following is a good portable alternative:phrase("name:", Codes, Rest)
- Checks for a character to be in a set
- Such tests are often performed with code such as this:
memberchk(C, "~!@#$")
. This is a rather inefficient check in a traditional Prolog system because it pushes a list of character codes cell-by-cell onto the Prolog stack and then traverses this list cell-by-cell to see whether one of the cells unifies with C. If the test is successful, the string will eventually be subject to garbage collection. The best code for this is to write a predicate as below, which pushes nothing on the stack and performs an indexed lookup to see whether the character code is in‘my_class'.my_class(0'~). my_class(0'!). ...
An alternative to reach the same effect is to use term expansion to create the clauses:
term_expansion(my_class(_), Clauses) :- findall(my_class(C), string_code(_, "~!@#$", C), Clauses). my_class(_).
Finally, the predicate string_code/3 can be exploited directly as a replacement for the memberchk/2 on a list of codes. Although the string is still pushed onto the stack, it is more compact and only a single entity.