[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: Icon



Icon does do its best to make everything an expression, including loops.
The description below is incorrect, however, in its assertion that loops
simply return a null value.  It is wrong in two ways, and one of them is
important.  (Icon is my favorite language, and it has features that
*none* of this list's well-represented languages have, e.g., string
scanning and goal-directed evaluation. http://www.cs.arizona.edu/icon/)

The unimportant error is the assertion that loops to not "return
anything interesting."  A loop can return anything you want it to
return.  Icon's "break" statement takes an optional expression as its
argument and that is the value returned by the loop.  (Actually, break
is more interesting than that, but I'll omit details here.)

The important error is the assertion that a loop returns "just a null."
Actually, a loop without a break returns *nothing* at all, which is
distinct from a null value.  The loop expression is said to "fail" to
generate a value.  This would have become apparent had  the local "foo"
below been initialized to a value, say 5.  The "display" of foo would
have shown a value of 5.  Why?  Because the while loop failed, which
meant that the assignment would fail and hence not overwrite the
previous value of foo.

So, I'll give a brief plug for Icon's goal-directed evaluation.
Goal-directed evaluation mirrors a fundamental concept better than any
alternative that I have seen---the concept of success and failure.  Most
programming languages have Boolean values, but almost never squirrel
them away in a variable.  They are almost always computed and then
immediately consumed as a predicate to some control-flow construct.
Thought of more generally than True vs. False, the control construct was
guided by the success or failure of some expression.  Icon does not have
a Boolean datatype, but it has made success and failure central to its
computational mechanism.  More over, it generalizes expression to become
"generators" that may produce zero or more values.  I.e., it succeeds in
producing values until it fails.  Notice that this is *more* general
than the functional world's handcuffed world in which every function
produces exactly one value.

Some examples are in order.  Since I'm guessing few of you have read
this far and fewer yet know Icon, I'll try to take an efficient path
from Hello World to some interesting goal-directed programs.  The
following is Hello World.

procedure main()
   write("hello world")
end

Nothing too exciting there.  To get more exciting, I have to explain a
little about goal-directed evaluation.  In GD, every expression
generates a sequence of values until it fails.  (It doesn't have to
fail---it could produce an unbounded sequence of values.)  So, before I
get to much more explicit, I'll start with some examples that are easier
to understand without perfect knowledge of what is going on.  My
favorite simple program in Icon is the following, which prints *3* lines
of output, "1", "2", and "3".

procedure main()
   every write(1 to 3)
end

The "every" statement creates a context in which the subsequent
expression tries to succeed as many times as it can.  Thus, "write"
tries to succeed as many times as it can.  Well, write takes an
argument, which is the generator "1 to 3".  This generator will produce
1, and then 2 and then 3 and then fail.  Well, what happens above is
that write gets 1 and writes it, then every gets write to try to succeed
again, but it cannot without another value from 1 to 3.

Now, the following produces 2, 3, 4.

procedure main()
   every write((1 to 3) + 1)
end

This works exactly the way you think it would, although you may not have
seen a language in which + can produce a sequence of values.

Of course, this begs the question of what the following will produce.

procedure main()
   every write((1 to 2) + (4 to 5))
end

It will produce 5, 6, 6, 7.  The generators are evaluated left to right
and, therefore, you get 1+4,1+5,2+4,2+5.

Of course, now you might say that this is all quite cute, but where is
the goal direction in all this?  Well, it's in the fact that each
generator is trying to succeed and will ping its operands for more
values in its quest to succeed as often as possible.  To see this, I
should show the '<' operator in Icon.  It is a numeric test that either
succeeds (if the left operand is less than the right operand) or it
fails.  If it succeeds, it produces the right operand.  Hence, 3<4
produces 4, but 5<2 simply fails.  So, it's time for another example.

procedure main()
   every write(4 < (1 to 6))
end

The program above produces 5,6.  How can this be so?  Well, it tries to
write(4<1), but because 4<1 fails, the write never actually gets called,
BUT write does not give up---it tries for a new value from '<' which
obliges by trying 4<2, which also fails, as does 4<3 and 4<4, but
finally 4<5 succeeds, so write can chew on 5 and then later on 6.

Now, I won't bother you further with all the details of Icon, but I will
add that Icon does allow user-specified generators and has lots of the
other features that you'd expect in a language.  (It lacks a bunch, too,
such as closures and continuations.)  I just know that now that I've
used a language with goal-directed evaluation, I never want to go back.
When I'm forced to, I do, but only as I grumble.

So, what does all this have to do with the
How-Will-Lisp-Gain-The-Place-It-Deserves-In-The-Hearts-And-Minds-Of-Prog
rammers-Around-The-Globe debate that consumes so much of this mailing
list?  (I've isolated three basic threads to this discussion (1) Real
Programmers Use Macros, (2) Real Programmers Aren't Afraid of
Parentheses, and (3) Real Programmers Understand Continuations.)  Well,
my missive has nothing to do with the great Lisp debate.  I just wanted
mention a beautiful language mechanism that's been ignored by virtually
all language designers.

Todd



-----Original Message-----
From: Richard Todd [mailto:rmtodd@ichotolot.servalan.com] 
Sent: Wednesday, December 19, 2001 6:44 PM
To: ll1-discuss@ai.mit.edu
Subject: 


In ll1-discuss Paul Prescod writes:
>Also, it is debatable what the "right thing" for an expression like 
>this to return is:

>k = while foo():
>       print "abc"
>       print "def"
>       print "ghi"

>I guess it would return None (Python's nil/null thing)? Allowing people

>to assign the results of a while loop just seems obfuscatory and thus 
>un-pythonic.

One of the things I found interesting about the Icon programming
language when I did some things with it several years ago was that,
unlike most other languages I'd seen, things that in other languages
were statements, like while loops, were expressions in Icon.  As you
suggest, while doesn't actually 
return anything interesting, just a null, as we can see from the
following
example:

32 ichotolot /tmp[ 8:41PM] Z% cat foo.icn  
procedure main()
  local foo, i
  i:=0
  foo := while(i<5) do {
	i +:= 1
	write(i)
  }
  write("============")
  display()
end
33 ichotolot /tmp[ 8:41PM] Z% ./foo
1
2
3
4
5
============
co-expression_1(1)

main local identifiers:
   foo = &null
   i = 5

global identifiers:
   display = function display
   main = procedure main
   write = function write

The display() function dumps the current state of all local and global
variables; as we can see, the assignment of the value from the while
loop set foo's value to null.