Because Mercury is purely declarative, the goal ‘Goal, fail’ is interchangeable with the goal ‘fail, Goal’. Also because it is purely declarative, there are no side effects to goals (see also the section on input and output). As a consequence of these two facts, it is not possible to write failure driven loops in Mercury. Neither is it possible to use predicates such as assert or retract. This is not the place to argue it, but we believe most programs that use failure driven loops, assert and retract to be less clear and harder to maintain than those that do not.
The use of assert and retract should be replaced with a collection data structure threaded through the relevant part of the program. Data which is truly global may be stored in the ‘io.state’ using the predicates ‘io.get_globals’ and ‘io.set_globals’. These predicates take an argument of type ‘univ’, the universal type, so that by using ‘type_to_univ’ and ‘univ_to_type’ it is possible to store data of any type in the ‘io.state’.
The standard library contains several abstract data types for storing collections, each of which will be useful for different classes of problems.
The ‘list’ ADT is useful if the order of the asserted facts is important. The ‘set’ ADT is useful if the order is not important, and if the asserted facts are not key-value pairs. If the asserted facts are key-value pairs, you can choose among several ADTs, including ‘map’, ‘bintree’, ‘rbtree’, and ‘tree234’. We recommend the ‘map’ ADT for generic use. Its current implementation is as a 234 tree (using ‘tree234’), but in the future it may change to a hash table, or a trie, or it may become a module that chooses among several implementation methods dynamically depending on the size and characteristics of the data.
Failure driven loops in Prolog programs should be transformed into ordinary tail recursion in Mercury. This does have the disadvantage that the heap space used by the failing clause is not reclaimed immediately but only through garbage collection, but we are working on ways to fix this problem. In any case, the transformed code is more declarative and hence easier to maintain and understand for humans and easier for the compiler to optimize.