Path: utzoo!attcan!uunet!munnari.oz.au!goanna!ok From: ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) Newsgroups: comp.lang.prolog Subject: Re: Standards question: behavior of arg/3 Keywords: ANSI, standard Message-ID: <4055@goanna.cs.rmit.oz.au> Date: 23 Oct 90 08:20:20 GMT References: <9888@bunny.GTE.COM> <3992@goanna.cs.rmit.oz.au> <1753@ecrc.de> Organization: Comp Sci, RMIT, Melbourne, Australia Lines: 215 In article <1753@ecrc.de>, micha@ecrc.de (Micha Meier) writes: > I completely agree with Richard O'Keefe that there should be just a few > design principles and everything else should depend on them. > The problem is, however, how to select these principles to obtain a sensible > system. I didn't find it all that hard. What did I overlook? > When we introduce built-in predicates to the language, the situation > changes, because not all of them can be defined as a set of axioms > of the language. (Let us leave out non-logical predicates, where > the situation is much clearer.) Eh? EPs fall into four categories: -- commands (change the state of the world) -- state functions (don't change anything themselves but are affected by commands) -- pseudo-predicates (don't depend on the state of the world, do depend on the instantiation state of their arguments, hence on evaluation order) -- pure predicates (don't depend on the state of the world) Pseudo-predicates can't be defined by (possibly infinite) sets of facts, but state functions and pure predicates can. The pseudo-predicates can, to the best of my knowledge, be defined in terms of var/1, nonvar/1, and possibly infinite sets of facts. > Those predicates, which can be defined > in Prolog, have then also a clear meaning and there seems no necessity > to introduce error messages. Let's keep things clear. Let's _not_ talk about error MESSAGES. Those are reports intended for human consumption. Let's talk about error detection and signalling. The design I did for Quintus last year split errors into four main groups: disasters Things went so badly wrong that the error handling system can't be entered. faults A query appears to make sense, but the Prolog system is unable to process it (not enough memory, numeric over/underflow, unsupported data type, file server dropped dead, and so on) errors a command could not be obeyed because an object identifier is malformed or fails to identify an object or the operation is not permitted, &c or a state function asking about some object couldn't be evaluated for a similar reason failures a query makes sense, and logically has the answer 'no', but it's most likely and error. (That's why I keep saying "instantiation FAULT"; what one Prolog will signal as an exception another may be able to handle by suspending.) Disasters and faults can happen at any time. Errors can only happen when it would be INCORRECT to fail. (For example, if I ask clause(true, Head, Body) either I should get a clause back, or I should get an error signalled because I have no permission to look at the clauses of true/0. It would be WRONG to fail here.) "failure" signals could well be optional; they are in effect run-type type checks. Disasters, faults, and errors have a very simple criterion: if the Prolog system can determine the correct answer (including failure as a correct answer) it should do so, and when and only when it is not able to determine the correct answer, that is either a disaster, a fault, or an error, depending on the reason why the correct answer can't be obtained. > However, when these logical principles are fully applied, > debugging programs becomes difficult. Oh? How? Exception detection and signalling is NOT repeat *NOT* a debugging feature. Exception handling is all about not producing incorrect answers. Debugging goes further. You might well call 'failure' messages, e.g. ! Type failure in argument 1 of arg/3 ! integer expected, but f(a,b,c) found ! Goal: arg(f(a,b,c), 1, _235) a debugging tool. I wouldn't quarrel with that. But it's not the only debugging tool. A programmer should be able to attach a "critic" to any predicate that will check lots of things which aren't technically errors. > Richard O'Keefe suggest that we apply the table method extensively, > but, exactly in case of arg/3, this would mean a different > semantics than in the vast majority of existing Prolog systems. Strictly speaking, it _would_ be different DEC-10 Prolog (but not from MU Prolog or IBM Prolog). But then so is producing error reports different! There is no real likelihood of the ISO version of arg/3 being eactly like DEC-10 Prolog's arg/3. A change which provides more CORRECT answers surely is no bad thing? We're not talking about taking _working_ programs and breaking them, we're talking about programs which didn't work properly and either reporting this fact or making them work properly. > in fact more like defining a new language, than to standardise > the old one. Not at all. There is prior art. We _can't_ be compatible with _every_ previous Prolog. There _are_ rough spots that have to be spelled out, and precisely because these were grey areas in the past we're going to differ from previous systems. It's important to minimise the differences. Extremely important. But extending the _specification_ of an EP to say that it works in cases which previously were not well defined, that's not much like defining a new language. > Another example may be is/2: > 5 is 3 + X > is completely logical and makes sense, however we cannot expect Prolog > to succeed here, even if the number of solutions is finite. No, the number of solutions here is not finite. Plug into X any ground arithmetic formula which evaluates to 2 and you have a solution: X = 2; X = 1+1; X = 0+2; X = -1+3; X = -2+4; ... The EP plus/3, however, *should* be solved in such a case: plus(3, X, 5) does have a unique solution for X, namely X = 5. (plus/3 only makes sense for rational numbers, not approximate numbers such as floats.) > The same concerns the query > X is fred (from O'Keefe's Standard paper) > which would fail if is/2 were defined with a table, but this > failure would not mean anything reasonable to the programmer. It's what I called a "type failure". It does mean something sensible: "'fred' is not an arithmetic expression." In QP you would get a message something like ! Type failure in argument 2 of is/2 ! Arithmetic expression expected but fred found ! Goal: _234 is fred If you want to switch this off, fine. There are precisely three reasons why a call Lhs is Rhs may fail: - Rhs is not a well-formed arithmetic expression - Rhs asks for a value which definitely does not exist (such as 1 // 0 or sqrt(-1.0)) - Lhs is already instantiated to something which doesn't unify with the value of Rhs If Lhs is a new variable, then only the other possibilities exist. > O'Keefe further says > < arg(N, T, A), > < !, % now we know that N >= 1 > > These are really bad arguments about the semantics of arg/3. If p/3 > is called with an integer which is possibly zero, there is no > need to push the work to arg/3: Hello Mr Thought Policeman! Yes, I *can* rewrite my code. Why *should* I? Why "push the work to" _me_? Why is it ok to break code that relied on a defined property of arg/3? Especially when you consider that I wrote PS/6 and sent it to the net back in 1984 precisely to make clear what it was that I _wanted_ to be able to rely on? The kind of argument here will apply to every kind of type and range checking. For example, concerning division by 0, "there is no need to push the work to _//_", we could allow X is Y//Z to return any random junk you like when Z = 0, the programmer *could* have written the code as ( Z =:= 0 -> signal_error(/* an appropriate error term */) ;/* Z =\= 0 */ X is Y//Z ). > < arg(3, Term, _) % if this succeeds, arity{Term} >= 3 > Why is it necessary to use arg/3 to test the arity of a functor > when we have functor/3?? The minimality principle has to be applied. Who said it was *necessary*? All I said was that it was *possible*; if I want to know whether there is a 3rd argument I can ask it directly without asking what the arity actually is. (As it happens I don't do that myself.) WHAT minimality principle? The BSI and ISO mobs have made much mention of a minimality principle, but they have never said what it IS. Let's see: if there is one way of doing something, there shouldn't be another? Right: then let us have (<)/2 alone, and not have (>=)/2, (>)/2, or (=<)/2; let us leave out (=)/2 because the user can define it, let us leave out (=..)/2 because the user can define it, let us leave out read/1 because the user can define it, let's leave out binary _-_, because we can always do -Y+X instead of X-Y, ... This is ridiculous. Let me be completely frank here: not only have I been unable to discover what the ISO mob mean by "minimality", the vague ideas I have about what it might mean seem for the most part to be very bad ideas. > We have some compatibility packages for other Prolog dialects, > and it is interesting to note that for C-Prolog, the only > events to redefine to make all our C-Prolog programs work > was the behavior of arg/3 and undefined predicates. It depends on which version of C Prolog you had. The 1.*.edai versions were a wee bit more thorough about reporting errors. > We do not insist that the standard does what we do, > but it is a very interesting experience to work with such a system, It sounds rather like QP. [I hope someone on the ANSI or ISO committees is keeping a copy of this stuff.] -- Fear most of all to be in error. -- Kierkegaard, quoting Socrates.