[REBOL] Comparing logic! [was Re: WYSIWYG programming]
From: joel:neely:fedex at: 28-Oct-2000 17:42
Hi, Brett,
[rebol-bounce--rebol--com] wrote:
> Hi Joel,
>
> > That sounds good. However, natural language and the common-sense
> > expectations of 'normal' people (or even programmers when they're
> > not programming) are notorious for their ambiguity and fuzziness.
>
> Important qualities that traditional computing cannot deal with.
>
This is not really an issue of "legacy" computing versus new-age
computing (or whatever one would call it ;-). Rather it is an issue
of whether it is important to be able to reliably state what will
happen. Consider all the various sciences, engineering, software
requirements, contracts, treaties, and all the branches of law.
It's A Good Thing if a line of poetry has multiple interpretations.
It's funny when an actor utters a line that has multiple meanings,
and then the plot takes various twists when different characters
act on those differences. But when I'm buying a house, applying
for health insurance, signing an employment contract, driving over
a newly opened bridge, reading the warranty on a product I just
bought, or using a programming language, I most definitely do not
want any surprises due to hidden meanings, fine print, ambiguity,
or obscurity.
I recall a conversation involving a lawyer and some non-lawyers who
were razzing him about how unreadable most contracts are. His
reply was, "You're absolutely right. But the purpose of contract
language is not to be readable; it is to be unambiguous."
> >
> > I humbly propose that the need for precision in programming means
> > that rigorous, elegant, and minimalist definition should take
> > priority over everyday conversational comfort, should they ever
> > come into conflict.
>
> Respectfully, I think you are putting up a language design goal
> that many (most?) computer languages have been aiming for for
> years. The same thing that many (most?) serious (experienced?)
> programmers would aim for in their programs. A mindset legacy of
> structured programming, provable programs, etc. There is nothing
> wrong with this - indeed it is necessary line of thinking, and up
> until recently I would have seconded your proposal for Rebol to
> follow this goal.
>
Let me state clearly, in case I have miscommunicated my view, that
I am NOT proposing nor advocating any radical changes to REBOL. I
am assembling a list of areas in which I feel the details could use
some polishing, and have attempted to explain my motivations for
that effort. I have also discussed some areas in which REBOL is
sufficiently unique (compared to the general field of prog. lang.)
or subtle (in and of itself) that special care may be needed in
documenting and explaining it.
However, I do not suggest that there's anything fundamentally "wrong"
with REBOL -- if I held that view, I simply wouldn't bother. There
are, after all, plenty of other programming languages.
> Now I think otherwise.
>
> 1) If feel that "rigorous", "elegant" and "minimalist" are from
> the Mathematical space of thinking.
>
Speaking as someone with a bit of familiarity with Mathematics (2+
degrees and 12 years teaching Math and Comp Sci), I agree. I must
add in passing that most folks find my definition of Mathematics
very different from what their academic experience has led them
to believe.
> Paradoxically, I think these concepts are very subjective.
>
If by "subjective" you mean "simply a matter of opinion" then I
disagree emphatically. If you mean "sufficiently subtle that they
cannot be defined in a 15-second sound bite" or "unlikely to be
assessed reliably by someone without significant experience", then
I wholeheartedly agree.
I don't want to sound elitist here, but let me give a couple of
analogies that I believe are valid.
A master carpenter can walk into a house that is at the stud-wall
level of construction and almost instantly spot a flaw in the
framing. However, it might take him several minutes to explain
exactly what's wrong -- and the negative consequences that could
occur -- to a someone who is a ignorant of house framing as I am.
It is quite possible, in fact, that my background is so limited
that I simply won't understand his concern no matter how carefully
he explains it (although that is probably very unlikely, not
because I know much about carpentry, but because most of the good
carpenters I've been around can explain what they do fairly well).
I've also had the experience of taking a car with one or two fairly
subtle symptoms to an expert mechanic who could almost interrupt me
before I finished my description and tell me what was wrong.
So it is with elegance in Mathematics (of which Computing Science
is a close relative).
> 2) I believe one of the main aims of Rebol is to be a useful
> language. Its practical and pragmatic approach has been the
> selling factor for me to invest my time in it. That said, I do
> agree with you (and others) that it needs a more detailed
> supporting documentation set on the language, but I can accept
> that the language itself is still stabilising.
>
Agreed on all points. Actually, some folks are surprised that I
consider one of the most endearing properties of Perl that it is
conceptually much closer to natural (human) languages than it is
to most programming languages.
> 3) "precision in programming" reminded me of the often heard
> "Arrgghh! It did what I said, not what I meant!". I'm hoping
> that Rebol will succeed in reducing the occurrence of this
> phrase via dialecting.
>
Dialecting is a nice device -- and REBOL is not the only language
that uses such a device. However, it's just a device, and poor
design can afflict dialects as well as entire languages.
> I hope you don't find my comments frustrating - I am deliberately
> "coming in from a different angle". They are meant to invite the
> questioning of perhaps long held "truths". In the Rebel fashion ;)
>
Quite the contrary! Probing such a topic from as many angles as
possible is one of the most effective ways to understand it, IMHO.
I certainly spend enough time inviting questioning of perhaps more
recently held positions! (One of my favorite quotations says,
There are two kinds of fool in the world. One kind says,
"This is good because it's old." The other kind says,
"This is better because it's new."
> One last thing which has perplexed me with this whole thread.
> Your example of the ordering of logical values. Why?
>
The issue was not about an burning need for logic! values to be
considered as an ordered set. I was simply demonstrating an
inconsistency in how data values are handled. However, I admint
that this inconsistency is annoying to me, for reasons which I
illustrate below, following your next question.
REBOL lets me convert back and forth between logic! and integer!
data, with the correspondence that FALSE <-> 0 and TRUE <-> 1.
It also lets me compare/sort integer! values, but refuses to let
me compare logic! values, even though the correspondence above
clearly (to me, at least) is consistent with the interpretation
that FALSE < TRUE.
If I have two number! values, they compare in the same way as
their integer! equivalents. Two character! values also compare
in the same way as their integer! equivalents. Converting to
and from integer! preserves the ordering of these values.
It seems odd to allow ordering to be preserved over all the other
types that can interconvert with integer! and yet refuse to allow
that for logic! values.
> What do you use such a thing for?
>
Let me give a tiny example of how one could use that capability,
and why I view the inconsistency as too costly. Consider the
function defined as
tally: func [b [block!] /local c t v n] [
c: sort copy b
t: copy []
while [not tail? c] [
v: first c
n: 0
while [all [not tail? c v = first c]] [
n: n + 1
c: next c
]
append/only t reduce [v n]
]
t
]
This function just tallies up the number of occurrences of each
value in a block. If I have a block containing the ages of a
second-grade class,
ages: [7 6 7 7 8 6 8 7 7 6 6 7 7 8]
I can say
>> tally ages
== [[6 4] [7 7] [8 3]]
and learn that there are 4 six-year-olds, 7 seven-year-olds, and
3 eight-year-olds.
Bear in mind that the block could have been the result of user
input, or could have been extracted from data in a disk file, or
calculated from birthdates... it doesn't matter where the data
came from.
Sorting is a convenient way to group data for a variety of reasons,
and (depending on your application domain) Tally might be a handy
addition to your toolkit.
ALSO... We could write another function (using "ASCII art" in
/Core or /Command, or the graphical features of /View) which
would take an argument block, call Tally to get a summary, and
then draw a bar graph of the results, something like
6: ####
7: #######
8: ###
I won't bore everyone with the bar-graphing code, but my point is
that once we have Tally, we may use it either stand-alone, or
build on it to define other additions to our re-usable library.
Our little Tally function can also handle other data. Suppose
I have the home states of a group of people.
homestates: ["TN" "CA" "NY" "CA" "TN" "WA" "CA" "WA" "AR" "TN"]
>> tally homestates
== [["AR" 1] ["CA" 3] ["NY" 1] ["TN" 3] ["WA" 2]]
Now, suppose I have a block that tells me whether each of a group
of people are going on the company picnic.
>> picnic: reduce [yes no no yes yes no yes yes yes no yes yes]
== [true false false true true false true true true false true true]
(Remember, that 'yes 'no 'on 'off 'true 'false are just words that
are predefined to REBOL logic values TRUE and FALSE. I reduced the
literal block in this example to get "real" logic! data, which we
would have gotten if we were producing the true/false values from
other code.)
>> tally picnic
== [[false 4] [true 8]]
Notice: REBOL SORTS LOGIC! VALUES, using the same implied order that
we would infer from the corresponding integer values -- FALSE < TRUE.
Now, back to our Tally function... Suppose I have some student test
scores...
scores: [90 95 90 100 85 90 90 80 95 90 100 95 100]
...and I am mostly interested in the top performers. I can certainly
use Tally for that purpose...
>> tally scores
== [[80 1] [85 1] [90 5] [95 3] [100 3]]
...but wouldn't it be nice if I could see them in highest-to-lowest
order as well?
Guess what? Sort lets me supply a comparison function to cause the
ordering to be whatever I want. Let's take advantage of that to
make a nicer Tally.
tally: func [b [block!] /compare f [function!] /local c t v n] [
c: copy b
either compare [
sort/compare c :f
][
sort c
]
t: copy []
while [not tail? c] [
v: first c
n: 0
while [all [not tail? c v = first c]] [
n: n + 1
c: next c
]
append/only t reduce [v n]
]
t
]
Now I can say
>> tally/compare scores func [a b] [a > b]
== [[100 3] [95 3] [90 5] [85 1] [80 1]]
as well as
>> tally/compare homestates func [a b] [a > b]
== [["WA" 2] ["TN" 3] ["NY" 1] ["CA" 3] ["AR" 1]]
but if I try to say
>> tally/compare picnic func [a b] [a > b]
** Script Error: Cannot use greater? on logic! value.
** Where: a > b
So, I ask you, what sense does it make for REBOL to allow sorting
of values that it refuses to compare???? Doesn't common sense
(using either your sense or mine... ;-) lead us to believe that
sorting is just repeated comparison and shuffling among a bunch
of data values? Grumble, grumble, grumble...
SO NOW... In order for Tally to be as re-usable as possible, we
either need to complicate Tally with a check on the data in the
argument block (and have it ignore any custom comparison in the
case of logic! values), or we have to remember never to use
custom comparison functions with logic! values ... WAIT A MINUTE!
Remember our imaginary bar-graphing function that could be based
on Tally? Now we have to worry about whether it may call Tally
with custom comparisons as well...
Oh, what a tangled web we weave
When first we practice inconsistency!
Inconsistency puts all kinds of sand in our shoes when we start
trying to write general, reusable code. Hence my strong personal
preference for rooting it out as early as possible!
Hope this helps put my grumpiness into perspective! ;-)
-jn-