Re: Ann: SWI-Prolog 6.5.3
"Richard A. O'Keefe" <[email protected]>
| Newsgroups | gmane.comp.ai.prolog.swi |
|---|---|
| Message-ID | <[email protected]> |
On 20/11/2013, at 10:43 PM, Jan Wielemaker wrote:
[about the new behaviour of memberchk/2]
> I'm surely not proud of this. On the other hand runtime (type) checks
> have never guaranteed type correctness.
I don't quite get the "on the other hand" here. That's one of the
grounds of my complaint.
I quite understand the *point* of the change, and seeing all the work
that went into dealing with robustness against changes to the meaning
of double quotes (which was only a good idea _politically_, not
_technically_) I can definitely see where this is coming from.
I guess my basic point is the *inconsistency*,
- that one predicate checks and closely related ones don't
- that it checks some things but not others,
- long after the file is loaded,
which mean that the result is a check you cannot *rely* on.
That is, if I want to write code that is robust against double quote
changes, I have to do something *else* anyway, and whatever that else
is, it's likely to be *more* effective than this particular change.
> Subsequently, if this error is not a logical error, you can
> make your program clearer my putting an explicit type test before the
> predicate that would raise the exception.
In this case, as you yourself made quite clear, that's not so.
A call to memberchk/2 may now blow up at _any_ point along the
second argument, which means that the explicit type test to
prevent it must check _every_ point along the second argument.
The sheer cost of doing the type check dynamically is why
append([a], b, [a|b]) works.
> Now, from a typing perspective, I think we should consider any list that
> does not `terminate' in [] or a (constraint) variable an ill-typed data
> structure.
Again, I think the key idea is *consistency*.
If I set up my own lists using nil/0 and cons/2 then I
want the them to be treated *exactly* like []/0 and (.)/2.
If they are not treated in *exactly* the same way (mutatis
mutandis) then the language becomes much harder to think
about. To be specific, consider
memchk(X, cons(H,T)) :- ( X = H -> true ; memchk(X, T) ).
If this behaves differently from memberchk/2, you make my
life as a programmer *HARDER*.
> Ideally, we'd have infrastructure that avoids that these are
> created in the first place. It is a bit hard to see an efficient runtime
> solution for that. Probably only static type analysis can give you that.
A static type checker can be optional, like the one in Erlang, the
one in Racket (né PLT Scheme), and the one Lee Naish did for NU Prolog.
>
> If we consider getting rid of [a|b] a separate problem, memberchk/2
> now basically simply checks that the second argument is a list.
Can we please consider "getting rid of [a|b]" a *non*-problem?
Amongst other things, the type check in memberchk/2 DOESN'T
directly address it.
?- memberchk(X, [a|b]).
will succeed with X = a. An *unreliable* test (defined as an alarm
that sometimes goes off when a fault is present and sometimes FAILS
to go off when what's arguably the *same* fault is present) is not
to be trusted.
> This
> raises some exceptions on existing code. Most of the cases I studied
> should be considered highly dubious code. I found only one case where
> one could reasonably state that silent failure was anticipated.
One case is arguably one case too many.
>
> I agree here. The only way to make strings cooperate with list
> predicates is to make strings appear as virtual lists on which you can
> apply normal (list) unification. You claimed that NU-Prolog does this
> and that it is far from simple (if I recall correctly).
Well, what counts as "far from simple" in a system that has to fit
into 4MiB and what counts as "far from simple" in a system that can
use 4 GiB or more aren't the same thing. SWI Prolog is a much bigger
system than NU Prolog ever was and has been for some time. My
understanding is that the code required *care* but not great cleverness.
> Even if
> possible, I still do not like that, as it will imply that strings may
> silently be transformed into code lists.
Now I am puzzled and confused. The point of the NU Prolog approach
was that strings *were* lists, it's just that some strings were stored
more compactly than others. It meant, for example, that you could have
large amounts of text data in static code.
For a rather good analogy, consider dear old CDR-coding.
The effect of CDR-coding is that some lists are stored rather like
arrays (with 1 word per element). Garbage collection might turn
some 2-word-per-element (parts of) lists into 1-word-per-element ones.
Some processing might go the other way. But that's an invisible
implementation detail.
In the same way, in the NU Prolog approach, a byte-per-element string
*IS* a code list, just stored differently.
Since SWI Prolog lets you do anything you might ever have wanted to do
with strings using atoms, it's not clear that SWI Prolog gets any
benefit any longer from having strings at all.
> Overloading all list predicates
> is (IMHO) a similarly bad idea.
Nobody suggested overloading _all_ list predicates.
>
>> What we *want* is the style check.
>> :- style_check(+double_quote).
>> should warn any time a double-quoted literal is passed to a
>> "well known" list-processing predicate.
>
> There is something like that in the V7 branch. It is part of
> library(check), called list_strings/0. It analyses the loaded program,
> looking for string literals that are passed to arguments of predicates
> that are not known to be safe.
library(check) is nice to have, but that check answers the wrong
question. The question is,
- I have some code,
- it is being loaded with the default flags,
- there are NO strings in it NOW,
- but WILL it give me problems IF loaded with
double_quotes set differently?
I am _never_ going to spontaneously write code that I intend to
be loaded with double_quotes set differently. But I would be
happy to know that my code _would_ work for people who choose
otherwise. (I would expect the style check to let you
characterise additional predicates.) I certainly don't want to
have to load something with flags set "wrongly" to check it,
lest I forget to change them back.
> For example, calling format("Hello
> world!~n") is supposed to be fine, but append("hello", Rest, List) is
> not. It allows declaring additional predicates as `safe'.
Does this mean that _every_ predicate (or rather, every argument
position of every predicate) is presumed dangerous unless declared safe?
Now consider
p(X) :-
OK = "fubar",
memberchk(X, OK).
[By the way, typing help(...) to SWI Prolog on a Mac takes AGES.
Even with the SWI-Prolog.app, it starts X11, and it can take a
couple of minutes of frustration watching the X icon bounce.
How do I tell it to display the help text to the terminal,
glass TTY fashion? Seriously, it's quicker for me to telnet
over to my Solaris 10 box and fire up SWI there. I just did
exactly that.
]
Here's text from an elderly swipl.
double_quotes (codes,chars,atom,string, changeable)
This flag determines how double-quotes strings are read by
Prolog and is ---like character_escapes--- maintained for each
module.
What I _want_ is to be able to declare in a source file what
syntax settings that file is to be processed with *without* any
effect on run time. Is that possible?
help 4 minutes ago and it _just_ settled down and g