I spent a few hours with my grandson yesterday, although he didn't have much to say for himself. His elder sister whose second birthday will be in another two weeks' time was most soliticious, with remarks like "baby's sleeping" and "baby's bottle". She hasn't got to the stage where she might become envious of how much time and attention her brother is taking from her parents that used to be devoted solely to her.
I travelled to Karmiel on Thursday, a day on which I prefer not to travel as the trains are generally more occupied then during the week. It is said that this year's flu is more virulent than usual and that masks are recommended for the over 65s. I was the only person that I saw who was wearing a face mask despite having been vaccinated a few months ago. Despite the mask, I can feel slight discomfort when I swallow; I hope that this won't develop into anything as I have to be in full health on Monday for the baby's brit.
After dealing with such quotidian matters as walking the dog, cooking dinner and watching the news on television, I had time to devote to extending my Prolog interpreter. There were a few standard built-in predicates that I wanted to implement; except for one, this work was straighforward. Length returns the length of a list, so a list like [a, b, c] has length 3 as does as a list like [a, [b, c], [d, e]]; this latter has only three elements, even though some of those elements are themselves lists. At the moment, I can't see what one would do with this predicate although presumably there is some reason.
Another predicate to be implemented was nonvar that succeeds (evaluates to true) if its argument is currently not a free (uninstantiated) variable. This is needed for what can be termed the fast_reverse rules (Covington et al., p 79) that reverses an n-element list in n+1 steps, as opposed to the naïve Lisp-like reversal which is O(n²). This usage very much justifies the need for the predicate.
Another simple addition was to make the interpreter load on startup a file called 'startup.pl' if it exists. At the moment this file contains the 'member', 'append', 'fast_reverse', 'add', 'subtract', 'multiply', 'divide' and 'modulo' rules so these don't have to be defined manually.
Later, a group of three predicates - retract, asserta, assertz - were added; these have similar structures. Retract removes a fact from the knowledge base whereas asserta adds a fact at the beginning and assertz adds a fact at the end. Adding retract was straightforward as initially assertz seemed to be, but the latter caused problems. I could see in the implementation of the predicate itself that the fact was being added, but when I came to show or even query the knowledge base, the fact had partially disappeared. In order to track this bug, I single stepped from the stage where the fact was added. One forgets that queries are invoked from a procedure called DoQuery that calls the recursive ResolveQuery function; this procedure sets up certain variables, calls the resolution, prints the solutions then clears memory allocated during the query. It was this garbage clearing that was causing the problem: the interpreter is in 'query mode' when assertz is called, and as a result, terms created are added to the query heap which is then cleared after the query completes. This is the reason that the fact disappeared. Once I saw this, the fix was clear: at the beginning of asserta/z, the 'querying' flag should be set to false, so that created terms will be added to the correct heap; the flag is restored at the end of the procedure.
CoPilot didn't consider this problem when it was trying to establish why the fact was apparently disappearing, although it should have 'known' that we torture tested the interpreter the week before when implementing 'append', and so this sort of problem should come from somewhere that wasn't tested then. Mind you, garbage collection didn't suggest itself to me either. Tracking down this bug reinforced the saying that debugging is 99% finding where the bug occurs and 1% fixing it.
These predicates allowed a certain amount of refactoring as some of the code is common. Reading the Covington book more closely showed that before these predicates can be used, the predicate to be affected should be marked as dynamic; this is a new flag that will have to be added to a term. The implementation seems to be straightforward, and the flag checked before a fact is removed. Following on from this are two more predicates, retractall and abolish.
My discussion of these predicates is based on the following facts
parent (noam, netta). parent (noam, nir). parent (sarit, netta). parent (sarit, nir).
Assuming that parent has been marked as dynamic, then ?- retract (parent (noam, netta)). would remove the first fact from the database leaving the other three undisturbed. ?- retractall (parent (noam, _)). would remove the first two facts, ?- retractall (parent (_, netta)). would remove the first and third facts, and ?- retractall (parent (_,_)). should remove all the facts. ?- abolish (parent/2). should remove all the parent facts, regardless of whether the predicate has been marked as dynamic. Note that this predicate appends the predicate's arity to its name; arity is a fancy way of saying how many arguments a predicate has - Prolog allows a predicate to have different numbers of arguments, in which case the name of the predicate is the same but the arity is different and so these are not the same predicate. At the moment, the interpreter doesn't handle arity as such; this is something that I can (and should) easily add.
The word arity itself comes from combining the Latin-derived suffix -ary (from words like unary, binary, ternary, meaning "in groups of") with the suffix -ity (denoting a state or quality). Together a term is formed for the "quality of being n-ary," or the number of arguments/operands a function/operation takes in logic, math, and computer science, first appearing in English around the 1960s. It's synonymous with adicity (from Greek roots like monadic, dyadic) and refers to the count of inputs, e.g., a function with two inputs has arity 2.
I had a Prolog dream last night: a senior policeman, Superintendant Brown, was in charge of the project that was implementing Prolog for the police. It was discovered that he (and a crew of hired men) had robbed a property (or maybe a museum): he had been filling the Prolog database with facts about the property's security (how many cameras, motion detectors, etc were in the property and where they were placed) then used Prolog's goal solving capability to find a way to get around all the security measures and steal whatever was stolen. My aims are slightly less nefarious; I want to find a defintion of the puzzle where a fox, a goat and a cabbage all have to be transported across a river. If the fox and goat are left together then the fox will eat the goat; similarly, if the goat and the cabbage are left together then the goat will eat the cabbage. Obviously the fox has to be left with the cabbage.
But before I can get to such interesting work, I have to deal with more quotidian matters like learning how to drive the hybrid car that we inherited from my late brother in law, and doing some consulting work that will actually earn me a few pennies.
| Title | Tags | ||
|---|---|---|---|
| 317 | Frustration in the computer lab | Computers, Firebird | |
| 908 | Zero values in Priority tables - a blessing and a curse | Priority tips | |
| 1281 | Another black Friday | Obituary, Kibbutz |
No comments:
Post a Comment