Saturday, October 25, 2025

Implementing CP Prolog - 5

The goal of this week's installment is to parse, print and solve correctly a query such as
?- time_in_minutes (05:40, X), according to the rule shown below. If everything goes correctly, then X = 340 should be the result. 5 hours after midnight is 300 minutes, along with another 40 minutes. Here's the rule:
time_in_minutes(TimeAtom, Minutes) :- atomic_list_concat(TimeAtom, ':', [HStr, MStr]), atom_number(HStr, H), atom_number(MStr, M), Minutes is H * 60 + M.

The code from last week is line-orientated: it reads each line as a separate fact, rule or query, deleting the final full stop (in fact, frequently I would omit the full stop when typing as it didn't do anything). In order to read the above correctly, each line has to be concatenated in a buffer until a full stop is read at the end of a line (a full stop in the middle of a line should be ignored at this stage). The fix for this had to be implemented in two places: in the main loop that reads user input, and in the procedure that loads a text file.

Parsing the rule was more difficult. The head (i.e. time_in_minutes) was read correctly, but when I tried to query using this predicate, the first and only subgoal that appeared had the 'is' predicate. Obviously all the subgoals until the final one were being ignored. I tracked this down to a location where the presence of an inline operator in the line is checked before dividing the line into parts. This is a direct result of the queries that I was writing last week, such as add (Operand1, Operand2, Result):- Result is Operand1 + Operand2. I hadn't considered the possibility that the rule might have several clauses, where not all of them had inline operators. Once I found the problem, solving it was fairly simple: first divide the body (i.e. list of subclauses) into separate clauses, then handle each clause on its own. 

So the rule's body has four clauses, where the final clause is a 'triple whammy': three infix operators. This should be translated into the form: is (Minutes, * (H, + (60, M))). Now this complex term is built correctly.

The same problem of assuming that if the rule's body has an infix operator occurred in the printing (or 'showing') code. Again, each clause should be handled on its own, where the final clause gets passed to the recursive PrintInline function. Now the rule is printed correctly.

The rule assumes two intrinsic predicates, atomic_list_concat and atom_number. The latter is probably easier to understand; if the variable (first argument) is a number, return its value in the second argument. So if HStr has the atomic value '05' then H should be 5. The first predicate splits an atom whose value is <something> colon <something> (e.g. 05:40) into a list, where the first entry in the list will be 05 and the second 40. It's just as well that I did some work on lists, although I don't know whether it will be sufficient for this case.

For some unknown reason, I had modified the first clause in the rule and all my debugging was on this one clause.

?- atomic_list_concat ([H|M], ':', 04:30).

Maybe this is what I had originally and CoPilot changed it. Whatever. This query required all kinds of changes and I spent hours on it. Parsing and printing had to be changed to allow this new kind of list, [H|M]. Resolution also required changes. Despite the myriad changes, for quite some time the solution to the above query was H=H, M=M, which is a clear sign that the environment is not being updated somewhere. CoPilot says the environment should be passed as a VAR variable everywhere so I changed this wherever necessary. Now H= 04 and M = 30. Halleluya!

I don't have the necessary strength of will to implement the predicate 'atom_number' at the moment. I'm fairly sure that it's called something else in other implementations. At the moment, it won't actually do much - the term's name '30' will be replaced by '30' because name is a string field, but '04' should be replaced by '4'.



This day in blog history:

Blog #Date TitleTags
1925/10/2005The Time Traveler's WifeLiterature, Robert Silverberg, Time traveler's wife
21225/10/2009The importance of building indexesProgramming, SQL, Firebird
89625/10/2015The end of summer timePersonal
98425/10/2016What I did on my holidaysDBA, MIDI, Steig Larsson
143125/10/2021Blind date (new song)Song writing, Home recording
153925/10/2022Roland J-6 minisynth: a serious musical instrument or an expensive toy?Musical instruments, Roland J-6

No comments: