|Did you know ...||Search Documentation:|
|Why has the representation of double quoted text changed?|
Prolog defines two forms of quoted text. Traditionally, single quoted text is mapped to atoms while double quoted text is mapped to a list of character codes (integers) or characters represented as 1-character atoms. Representing text using atoms is often considered inadequate for several reasons:
Representing text as a list of character codes or 1-character atoms also comes at a price:
s("hello world")could be used to indicate that we are dealing with a string.
Lacking runtime information, debuggers and the toplevel can only use heuristics to decide whether to print a list of integers as such or as a string (see portray_text/1).
While experienced Prolog programmers have learned to cope with this, we still consider this an unfortunate situation.
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:
[X] = "a"is a commonly used template for getting the character code of the letter’a'. ISO Prolog defines the syntax
0'afor this purpose. Code using this must be modified. The modified code will run on any ISO compliant processor.
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)
memberchk(C, "~!@#$"). This is a rather inefficient check in a traditional Prolog system because it pushes a list of character codes cell-by-cell 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.
We offer the predicate list_strings/0 to help porting your program.