Re: Ann: SWI-Prolog 7.1.0
Jan Wielemaker <[email protected]>
| Newsgroups | gmane.comp.ai.prolog.swi |
|---|---|
| Message-ID | <[email protected]> |
Alan,
Good to point this out! Yes, if everyone follows the Craft of Prolog's
rules
on this, [] \== '[]' is not needed. But ..
- It uses a lot more memory (1 cell for joe and 3 for word(joe)).
- It makes switching on the _type_ of word(joe) fast, but switching
on word(joe) vs. word(john) slow. So, you need to be careful where
you wrap joe in word/1.
- It is kind of awkward to read.
- Most Prolog programmers have given up way before they understand
this part of this book (probably even before they bought the
book in the first place).
So, if we can fix all this (and some more) at practically zero cost,
it is an easy choice. The JPL issue is the only case to be taken
seriously. I think it is a design error in JPL though.
Cheers --- Jan
On 11/27/2013 05:30 PM, Alan Baljeu wrote:
> The discussion below (I've snipped some) is very valuable for
> every programmer to understand. To explain slightly (because 'defaulty'
> isn't a self-evident term):
>
> The idea is that if your datastructure uses named compounds to distinguish
> the possible content options, then you never have to write code that
> goes
> foo(X) :- atom(X), !, ....
> Instead you write
> foo(word(X)) :- ....
> and Prolog generates code without choicepoints and the code itself is
> easier to read and write.
>
> This argument demonstrates that atom(X) and empty_list(X) are unneeded in
> well-designed code. However, I fail to see the argument that atom([])
> is essential or good and not just a historical relic.
>
> Alan Baljeu
>
>
> ----- Original Message -----
> From: Richard A. O'Keefe <[email protected]>
> To: Prolog mailing list <[email protected]>
> Cc:
> Sent: Tuesday, November 26, 2013 9:55:28 PM
> Subject: Re: [SWIPL] Ann: SWI-Prolog 7.1.0
>
>
> On 24/11/2013, at 5:39 AM, Jan Wielemaker wrote:
>> In practical programming, you have cases where you have a list of
>> `tokens' (atoms) and you want to explode some tokens or other special
>> symbols into a sequence. The clean way is to use DCGs or difference list
>> to create a nice and flat holding the expansion. In some cases however,
>> it is way simpler if you can just explode the objects into lists, so you
>> get [ 'The', [quick, brown, fox], jumps, over, the, [lazy dog] ].
>
> Producing that kind of data structure would be exceedingly bad Prolog
> style *whatever* the empty list is represented as. It's the kind of
> data structure design that "The Craft of Prolog" calls "defaulty".
> Here elements are classified as "lists or non-lists". (Or should
> we say "owned by the emperor vs tremble as if mad".) The hell of
> that is that if an element isn't instantiated yet you can't _tell_
> what it is going to be. With *good* design, every possibility gets
> its own distinct tag:
>
> thingy = word(atom) | phrase(list(thingy))
>
> e.g.
>
> phrase([word('The'),
> phrase([word(quick),word(brown),word(fox)]),
> word(jumps),word(over),word(the),
> phrase([word(lazy),word(dog)]) ]).
>
> We can flatten that in perfect safety:
>
> thingy_words(word(X)) --> [X].
> thingy_words(phrase(L)) --> thingy_phrase(L).
>
> thingy_phrase([]) --> [].
> thingy_phrase([X|Xs]) --> thingy_words(X), thingy_phrase(Xs).
>
> This works even if some of the words are still unbound variables.
> The defaulty approach does not.
>
> We can with some caution adopt a different definition:
>
> thingy = word(atom) | [] | [thingy|thingy].
>
> -- note that this naturally and reasonably allows [word(so)|word(there)],
> constant-time concatenation just like Erlang iolists. It simply is not
> the case that all, or even all reasonable, uses of [_|_] are for lists,
> anymore than that all, or even all reasonable, uses of [] are for lists.
>
> thingy_words([]) --> [].
> thingy_words([A|B]) --> thingy_words(A), thingy_words(B).
> thingy_words(word(X)) --> [X].
>
> [word('The'),[word(quick),word(brown),word(fox)],
> word(jumps),word(over),word(the),[word(lazy),word(dog)]]
>
> Here again, each possibility for a thingy is flagged by a
> different functor: word/1, '[]'/0, or '.'/2. There is no
> way to mistake them, EVEN IF SOME OF THE WORDS ARE STILL
> UNBOUND VARIABLES.
>
> Non-defaulty data structures are good for efficiency because
> you get fewer choice-points created and need fewer cuts.
>
> With the defaulty version,
>
> thingy = atom | [] | [thingy|thingy]
>
> there _is_ an ambiguity between atoms and [] and worse still
> there is an ambiguity between unbound variables and everything
> else. So you have to write
>
> thingy_words(X) --> {var(X)}, !, ... what the heck goes here? ...
> thingy_words([]) --> !.
> thingy_words([A|B]) --> !, thingy_words(A), thingy_words(B).
> thingy_words(W) --> {atom(W)}, [W].
>
> If you design your data structures well, you never *care*
> whether [] is an atom or not except when you are writing
> meta-level code, in which case you care that it *is*.
> If you design defaulty data structures, nothing will save you.
> _______________________________________________
> SWI-Prolog mailing list
> [email protected]
> https://lists.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog
>