Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

LISP - When you've seen it, what else can impress?

267 views
Skip to first unread message

ilias

unread,
Sep 9, 2002, 11:06:07 AM9/9/02
to
This request is adressed to those people which have extensive knowledge
about different, if possible all avaiable historical and so called
modern language.

Which language should i take a look on?

Is there something, that can impress me?

I'm a LISP novice. But from what i've seen i can construct with this
language nearly everything i can imagine.

So the questions:

- which language out there gives me this freedom of construction?
- which language has some interesting constructs i could assimilate?
- is there any complete comparision of languages available, which gives
a quick overview?

I ask this in c.l.l., cause it relates to LISP.

Oleg

unread,
Sep 9, 2002, 12:00:32 PM9/9/02
to
ilias wrote:

[...]


> Which language should i take a look on?

ML, more specifically its O'Caml dialect. It's features include:

a) A langauge and an implementation in one (from the practical point of
view, this is an advantage, but see point "d"). Here I list features of
various importance for both.
b) Interpreter, virtual machine, and native compiler
c) Maximum portability (I know of people developing commercial Windows
products under Linux)
d) Open source (you are free to fork the implementation if you don't like
something)
e) A license that does not inhibit commercial use of your programs
f) Type inference (no need to declare types in function definitions)
g) Very strict type system: no overloading and no implicit conversions;
even printf is statically type checked!
h) Eager AKA strict execution model (as opposed to lazy as in Haskell)
i) Both functional and imperative programming (i.e. the language has
higher-order functions)
j) Both OO and non-OO programming
k) Abstract types
l) Polymorphism
m) Garbage collection
n) Automatic marshalling: no need to write serialization code (at least in
some/most cases)
o) Fast execution (IMHO, as a result of static type checking, run-time does
not need to type-check)
p) Good performance in programming contests
q) Easy C interface (both for calling O'Caml from C and C from O'Caml)
r) Lexical scoping, of course
s) O'Reilly book in French, and its English translation freely available on
the net (but not [yet] published)
t) Pattern matching

Cheers and pardon me/us for drifting off-topic.
Oleg

ilias

unread,
Sep 9, 2002, 12:29:11 PM9/9/02
to
Oleg wrote:
> ilias wrote:
>
> [...]
>
>>Which language should i take a look on?
>
> ML, more specifically its O'Caml dialect. It's features include:
>
...

>
> Cheers and pardon me/us for drifting off-topic.
> Oleg


pardon granted.

Thank you for you in-topic-reply.

i've not looked yet at: http://www.ocaml.org/

The language, from what you have written, sounds interesting.

What about the ability to generate code?

Is there any with the strength of CL?

Oleg

unread,
Sep 9, 2002, 1:15:58 PM9/9/02
to
ilias wrote:

Of course O'Caml programs can generate O'Caml code, and I don't see why it
should be any harder than in Lisp. Just like Lisp, O'Caml programs are
expressions, and you can even have prefix arithmetic operators: you can
write "(+) 5 7" or "((+) 5 7)" instead of "5 + 7", and also "(f (g (h x)))"
instead of "f (g (h x))" if you insist. Speaking of Lisp syntax in O'Caml,
I think O'Caml standard distribution even has a module for Lisp syntax that
lets it understand things like "(if a b c)" as "if a then b else c", but I
doubt that many people use it.

I personally never had much use for programs in language X that generate
programs in language X, especially if language X has higher-order
functions, but maybe others can't live wihtout it.

Oleg

ilias

unread,
Sep 9, 2002, 1:46:21 PM9/9/02
to
Oleg wrote:
> ilias wrote:
>
>>Oleg wrote:
>>
>>>ilias wrote:
>>>
>>>[...]
>>>
>>>>Which language should i take a look on?
>>>
>>>ML, more specifically its O'Caml dialect. It's features include:
>>
>>...
>>
>>>Cheers and pardon me/us for drifting off-topic.
>>>Oleg
>>
>>pardon granted.
>>
>>Thank you for you in-topic-reply.
>>
>>i've not looked yet at: http://www.ocaml.org/
>>
>>The language, from what you have written, sounds interesting.
>>
>>What about the ability to generate code?

i'm quoting uncontrolled:

> Of course O'Caml programs can generate O'Caml code

can you give me an example please?


> you can write "(+) 5 7" or "((+) 5 7)" instead of "5 + 7"

> and also "(f (g (h x)))" instead of "f (g (h x))"

> has a module for [...] syntax that

Can make syntax-modules myself?
Must i generate such a module to add a syntax?
Or can i change the syntax directly in a standard-program on the fly?

Oleg

unread,
Sep 9, 2002, 2:01:14 PM9/9/02
to
ilias wrote:

> i'm quoting uncontrolled:
>
>> Of course O'Caml programs can generate O'Caml code
>
> can you give me an example please?

Certainly. Here's an example of code for
a valid O'Caml program that generates code for
a valid O'Caml program that generates code for
a valid O'Caml program that generates code for
a valid O'Caml program that generates code for ....

AKA "the program that prints itself" (TM)

------ begin here ------------
---------- end here------------

It's small too. (0Mb)



>> you can write "(+) 5 7" or "((+) 5 7)" instead of    "5 + 7"
>
> > and also  "(f (g (h x)))" instead of "f (g (h x))"
>
>
>
>> has a module for [...] syntax that
>
> Can make syntax-modules myself?

Yes. http://caml.inria.fr/camlp4/manual/manual001.html

> Must i generate such a module to add a syntax?
> Or can i change the syntax directly in a standard-program on the fly?

Possibly. I use standard syntax. What is the nature of your obsession with
syntax?

Oleg

ilias

unread,
Sep 9, 2002, 2:29:16 PM9/9/02
to
Oleg wrote:
> ilias wrote:
>
>>i'm quoting uncontrolled:
>>
>>>Of course O'Caml programs can generate O'Caml code
>>
>>can you give me an example please?

you example looked like a marketing-gag.
have you an real-life-example? With code?

comparision: very simple CL

(defmacro dummy_m (var1 var2) `(+ (* ,var1 10) (* ,var2 20) )))
(deffun dummy_f (var1 var2) (+ (* var1 10) (* var2 20) )))

call of macro : (dummy_m 1 2)
call of function: (dummy_f 1 2)

(shows that syntax is the same. macro makes no sense here)

macros can be nested.

>>Can make syntax-modules myself?
>
> Yes. http://caml.inria.fr/camlp4/manual/manual001.html
>
>>Must i generate such a module to add a syntax?
>>Or can i change the syntax directly in a standard-program on the fly?

open question.

looks like no.

this is might good, to prevend programmers from making big desasters.

but i want to make disaster.

i looks like O'Caml cannot beat CL freedom.

Oleg

unread,
Sep 9, 2002, 2:55:15 PM9/9/02
to
ilias wrote:

> have you an real-life-example? With code?

An example of WHAT?! You wanted an example of a program that generates
code, I gave you the simplest one there is.



> comparision: very simple CL
>
> (defmacro dummy_m (var1 var2) `(+ (* ,var1 10) (* ,var2 20) )))
> (deffun   dummy_f (var1 var2)  (+ (*  var1 10) (*  var2 20) )))

let dummy_f var1 var2 = var1 * 10 + var2 * 20

> call of macro   : (dummy_m 1 2)
> call of function: (dummy_f 1 2)

dummy_f 1 2

> (shows that syntax is the same. macro makes no sense here)

If you want to change syntax RTFM. I posted a direct link.

Oleg

ilias

unread,
Sep 9, 2002, 3:30:51 PM9/9/02
to
Oleg wrote:
> ilias wrote:
>
>
>>have you an real-life-example? With code?
>
>
> An example of WHAT?! You wanted an example of a program that generates
> code, I gave you the simplest one there is.
>
>
>>comparision: very simple CL
>>
>>(defmacro dummy_m (var1 var2) `(+ (* ,var1 10) (* ,var2 20) )))
>>(deffun dummy_f (var1 var2) (+ (* var1 10) (* var2 20) )))
>
>
> let dummy_f var1 var2 = var1 * 10 + var2 * 20

this is the function.

where is the equivalent macro (codegenerator)?

>>call of macro : (dummy_m 1 2)
>>call of function: (dummy_f 1 2)
>
> dummy_f 1 2

again, where is the equivalent macro (codegenerator)?

>>(shows that syntax is the same. macro makes no sense here)

sorry, missleading! i meant:
macro makes no sense here (can and *should* use the function). Its only
for comparision-reasons, to show the nearly identical syntax.

> If you want to change syntax RTFM. I posted a direct link.

yes. for the tables.
http://caml.inria.fr/camlp4/manual/manual001.html


you can show me (and everyone whos watching) the way of altering the
syntax at program runtime. you know the language.

otherwise (for now) this become valid for me:

Dave Bakhash

unread,
Sep 9, 2002, 3:40:30 PM9/9/02
to
Oleg <oleg_i...@myrealbox.com> writes:

> > Must i generate such a module to add a syntax? Or can i change the
> > syntax directly in a standard-program on the fly?
>
> Possibly. I use standard syntax. What is the nature of your obsession
> with syntax?

Syntax has a lot to do with the Lisp language. Non-Lisp programmers
under-estimate the importance because they program in other languages
whose syntaxes are only minor variations of one another, and don't buy
the programmer very much. For CL programmers, the syntax, built-in
runtime reader and evaluator, and more are what make it so usable to
them. That's why they "obsess" over it.

dave

Kaz Kylheku

unread,
Sep 9, 2002, 4:20:40 PM9/9/02
to
When you've seen it, what can impress you is nice software that works.

Language *ideas* can still impress you, but not their manifestation
as some stupid new syntax, implemented from scratch over an inadequate
substrate.

People experimenting with new programming language semantics ideas
should be using Common Lisp rather than writing everything from
scratch.

Oleg

unread,
Sep 9, 2002, 4:36:53 PM9/9/02
to
Dave Bakhash wrote:

> Syntax has a lot to do with the Lisp language.  Non-Lisp programmers
> under-estimate the importance because they program in other languages
> whose syntaxes are only minor variations of one another, and don't buy
> the programmer very much.  For CL programmers, the syntax, built-in
> runtime reader and evaluator, and more are what make it so usable to
> them.  That's why they "obsess" over it.

I'm not an expert in macros, but IIRC I've seen an example of a "loop"
macro in Lisp that was used to demonstrate their usefulness. I'm not sure I
understand how using macros is any better than using higher-order functions
(HOFs) though.

E.g. to write a loop construct that increments its arument by 2 instead of
1, in O'Caml, I would write

let rec loop2 start finish f =
if finish < start then () else (f start; loop2 (start + 2) finish f)

which is probably close to what one could do with HOFs in Lisp. No need for
macros. Now

loop2 1 9 print_int

will print 13579. I guess the old saying that "if you don't know it, you
won't miss it" probably applies to me and Lisp macros here.

Cheers,
Oleg

ilias

unread,
Sep 9, 2002, 4:56:46 PM9/9/02
to
Oleg wrote:
> Dave Bakhash wrote:
>
>
>>Syntax has a lot to do with the Lisp language. Non-Lisp programmers
>>under-estimate the importance because they program in other languages
>>whose syntaxes are only minor variations of one another, and don't buy
>>the programmer very much. For CL programmers, the syntax, built-in
>>runtime reader and evaluator, and more are what make it so usable to
>>them. That's why they "obsess" over it.
>
>
> I'm not an expert in macros, but IIRC I've seen an example of a "loop"
> macro in Lisp that was used to demonstrate their usefulness. I'm not sure I
> understand how using macros is any better than using higher-order functions
> (HOFs) though.

...

> will print 13579. I guess the old saying that "if you don't know it, you
> won't miss it" probably applies to me and Lisp macros here.

i'm not sure. look here:

on page ... around 220 i think.
http://www.paulgraham.com/onlisptext.html

and im just writing in another topic, see actual posts "The Challange of
Nested Macros".

(did anyone know how i can reference to another threads, without
pointing to google?)

Alexey Dejneka

unread,
Sep 9, 2002, 11:33:24 PM9/9/02
to
Oleg <oleg_i...@myrealbox.com> writes:

> I'm not an expert in macros, but IIRC I've seen an example of a "loop"
> macro in Lisp that was used to demonstrate their usefulness. I'm not sure I
> understand how using macros is any better than using higher-order functions
> (HOFs) though.

Camlyacc is a stand-alone preprocessor. Zebu and Meta are lisp
libraries, you can mix parsers written with them with ordinary Lisp
code.

--
Regards,
Alexey Dejneka

Oleg

unread,
Sep 10, 2002, 12:24:16 AM9/10/02
to
Alexey Dejneka wrote:

Earlier in this thread, I was talking about Camlp4 (which is AFAIK
different from camlyacc), and in this particular posting I was asking
whether [Lisp] macros give you anything [O'Caml] HOFs don't [1]

As to changing the syntax in the same "compilation unit" (actually toplevel
session), I vaguely remember doing it while tinkering with Camlp4 and
following instructions in the tutorial. Interested parties should RTFM or
ask in ocaml-list.

Cheers,
Oleg

[1] HOFs have nothing to do with Camlp4, camlyacc, etc.

Matthew Danish

unread,
Sep 10, 2002, 3:00:57 AM9/10/02
to
On Mon, Sep 09, 2002 at 04:36:53PM -0400, Oleg wrote:
> Dave Bakhash wrote:
>
> > Syntax has a lot to do with the Lisp language.??Non-Lisp?programmers

> > under-estimate the importance because they program in other languages
> > whose syntaxes are only minor variations of one another, and don't buy
> > the programmer very much.??For?CL?programmers,?the?syntax,?built-in

> > runtime reader and evaluator, and more are what make it so usable to
> > them.??That's?why?they?"obsess"?over?it.

>
> I'm not an expert in macros, but IIRC I've seen an example of a "loop"
> macro in Lisp that was used to demonstrate their usefulness. I'm not sure I
> understand how using macros is any better than using higher-order functions
> (HOFs) though.
>
> E.g. to write a loop construct that increments its arument by 2 instead of
> 1, in O'Caml, I would write
>
> let rec loop2 start finish f =
> if finish < start then () else (f start; loop2 (start + 2) finish f)
>
> which is probably close to what one could do with HOFs in Lisp. No need for
> macros. Now
>
> loop2 1 9 print_int
>

Considering that Common Lisp can also express the same higher-order
function, perhaps you should consider why the LOOP macro is used. Or
any macro for that matter. It has already been demonstrated with the
lambda calculus that you can implement program control flow using only
functions. Do you see people doing that? Why have a WHEN macro when
you can just do (cond (... ...) (t nil)) ?

On a lighter note:

If you want to have some fun, why not write a nice higher-order function
to do:

(defun silly-loop (string &optional (increment 1) (final-char nil))
(loop for n from 0 by increment
for char across string
until (eql char final-char)
collect char into char-bag
sum n into sum
finally (return (values char-bag sum n))))

Try to make it half as readable. And as efficient.

(If you don't behave, I'll break out a 36-line perverse combination of
LOOP and FORMAT and make you do that one ;) (or perhaps that 30 line
LOOP which parses mbox files, I have somewhere)

> will print 13579. I guess the old saying that "if you don't know it, you
> won't miss it" probably applies to me and Lisp macros here.

There's also that old saying: "If you don't know it, you probably don't
know enough to compare it against something else"

(Not that I'm any less guilty of that at times =)

--
; Matthew Danish <mda...@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."

Matthew Danish

unread,
Sep 10, 2002, 3:14:01 AM9/10/02
to
On Mon, Sep 09, 2002 at 01:15:58PM -0400, Oleg wrote:
> Of course O'Caml programs can generate O'Caml code, and I don't see why it
> should be any harder than in Lisp. Just like Lisp, O'Caml programs are

Unlike Lisp, O'Caml programs aren't structured data.

> expressions, and you can even have prefix arithmetic operators: you can
> write "(+) 5 7" or "((+) 5 7)" instead of "5 + 7", and also "(f (g (h x)))"
> instead of "f (g (h x))" if you insist. Speaking of Lisp syntax in O'Caml,
> I think O'Caml standard distribution even has a module for Lisp syntax that
> lets it understand things like "(if a b c)" as "if a then b else c", but I
> doubt that many people use it.

It amazes me that you could read a Lisp newsgroup, and presumbly be
somewhat familiar with Lisp, and yet be so short-sighted as to be blind
to all but the first-level syntax.

You do know that there's more to Lisp syntax than prefix arithmetic
operators? Or the ubiquitous usage of parenthesis? Lisp syntax in a
language lacking the power to exploit it is a waste of time (although it
might make source code mungers easier to write).

> I personally never had much use for programs in language X that generate
> programs in language X, especially if language X has higher-order
> functions, but maybe others can't live wihtout it.

C programmers get by without higher-order functions. (somehow)

Matthew Danish

unread,
Sep 10, 2002, 3:25:29 AM9/10/02
to
On Mon, Sep 09, 2002 at 12:00:32PM -0400, Oleg wrote:
> ilias wrote:
>
> [...]
> > Which language should i take a look on?
>
> ML, more specifically its O'Caml dialect. It's features include:
>
> a) A langauge and an implementation in one (from the practical point of
> view, this is an advantage, but see point "d"). Here I list features of
> various importance for both.
> f) Type inference (no need to declare types in function definitions)
> g) Very strict type system: no overloading and no implicit conversions;
> even printf is statically type checked!
[omitted many things that can be found on web sites]

a) From the practical point of view, this is an advantage...
to the implementors. But not to the users, who cannot be guaranteed
a stable language even, who cannot be guaranteed that the latest
whims of the compiler team won't break their code, who have no
recourse in case of such breakage except to "go fork off".

f,g) Have you tried evaluating this, lately?: let rec f () = f;;

But that's unfair, really. It's good to experience a static type
system; one never knows true freedom until it has been lost, after
all. =)

Oleg

unread,
Sep 10, 2002, 3:45:32 AM9/10/02
to
Matthew Danish wrote:

> a) From the practical point of view, this is an advantage...
> to the implementors.  But not to the users, who cannot be guaranteed
> a stable language even, who cannot be guaranteed that the latest
> whims of the compiler team won't break their code, who have no
> recourse in case of such breakage except to "go fork off".

I think core ML of O'Caml is reasonably stable. AFAIK most _users_ use core
ML (stable features), while language developers tinker with things like OO
and polymorphic constructors.

> f,g) Have you tried evaluating this, lately?: let rec f () = f;;

Did you mean "let rec f () = f ()" ? - infinite loop as intended.
What's the problem?

Oleg

Oleg

unread,
Sep 10, 2002, 4:53:40 AM9/10/02
to
Matthew Danish wrote:

>
> If you want to have some fun, why not write a nice higher-order function
> to do:
>
> (defun silly-loop (string &optional (increment 1) (final-char nil))
> (loop for n from 0 by increment
> for char across string
> until (eql char final-char)
> collect char into char-bag
> sum n into sum
> finally (return (values char-bag sum n))))
>
> Try to make it half as readable.  And as efficient.

let silly_loop ?(increment = 1) ?(final_char = '\000') s =
let sum = ref 0 and i = ref 0 and char_bag = ref [] in
let _ = try while true do
char_bag := s.[!i] :: !char_bag;
sum := !sum + !i;
if List.hd !char_bag = final_char then raise Exit;
i := !i + increment;
done
with _ -> () in (!char_bag, !sum, !i);;

Cheers
Oleg

Joe Marshall

unread,
Sep 10, 2002, 9:20:43 AM9/10/02
to
Oleg <oleg_i...@myrealbox.com> writes:

Gee. Without all those parethesis in the way Oleg's version is
*much* more readable. (Although it could use a few more curly
braces and perhaps a dollar sign or two.)

Fernando Rodríguez

unread,
Sep 10, 2002, 10:42:38 AM9/10/02
to
On Mon, 09 Sep 2002 12:00:32 -0400, Oleg <oleg_i...@myrealbox.com> wrote:

>ilias wrote:
>
>[...]
>> Which language should i take a look on?
>
>ML, more specifically its O'Caml dialect.

Can't tell about ocaml, but Erlang and Oz seem to have some interesting
features.

-----------------------
Fernando Rodriguez

Marco Antoniotti

unread,
Sep 10, 2002, 11:06:47 AM9/10/02
to

Oleg <oleg_i...@myrealbox.com> writes:

> [1] HOFs have nothing to do with Camlp4, camlyacc, etc.

What is HOF? (Note that I know about Camlp4)

Cheers

--
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group tel. +1 - 212 - 998 3488
715 Broadway 10th Floor fax +1 - 212 - 995 4122
New York, NY 10003, USA http://bioinformatics.cat.nyu.edu
"Hello New York! We'll do what we can!"
Bill Murray in `Ghostbusters'.

Oleg

unread,
Sep 10, 2002, 11:10:33 AM9/10/02
to
Marco Antoniotti wrote:

>
> Oleg <oleg_i...@myrealbox.com> writes:
>
>> [1] HOFs have nothing to do with Camlp4, camlyacc, etc.
>
> What is HOF? (Note that I know about Camlp4)

Higher-order function (a function that takes and/or returns functions).

Cheers
Oleg

Immanuel Litzroth

unread,
Sep 10, 2002, 11:26:34 AM9/10/02
to
>>>>> "Oleg" == Oleg <oleg_i...@myrealbox.com> writes:

Oleg> Dave Bakhash wrote:
>> Syntax has a lot to do with the Lisp
>> language.  Non-Lisp programmers under-estimate the
>> importance because they program in other languages whose
>> syntaxes are only minor variations of one another, and don't
>> buy the programmer very
>> much.  For CL programmers, the syntax, built-in
>> runtime reader and evaluator, and more are what make it so
>> usable to
>> them.  That's why they "obsess" over it.

There is an interesting paper on Simon Peyton Jones website:
"Template Meta-programming in Haskell".
Immanuel

Rob Warnock

unread,
Sep 10, 2002, 11:32:27 AM9/10/02
to
Matthew Danish <mda...@andrew.cmu.edu> wrote:
+---------------

| > I personally never had much use for programs in language X that generate
| > programs in language X, especially if language X has higher-order
| > functions, but maybe others can't live wihtout it.
|
| C programmers get by without higher-order functions. (somehow)
+---------------

C supports higher-order functions. In fact, they're used quite
heavily in the Unix kernel code (well, at least in Irix, though
AFAIK the code I'm thinking of also exists in BSD) to do stuff
like MzScheme's "hash-table-for-each" or CL's "maphash", not to
mention the ubiquitous use in GUIs of functions which accept other
"callback" functions as arguments.

What C doesn't have built-in is *closures*! As a result, HOFs in C
almost universally resort to faking it with a separate argument to
the HOF which is an opaque cookie to be passed to one of the other
arguments, itself a function. So instead of CL's "maphash" signatures:

(maphash function hash-table) => nil
where: (function key value) => nil

you end up with something like this:

void
walkhash (ht_t table,
void (*fcn)(ht_t table, void *cookie, void *key, void *value),
void *cookie);

where the "walkhash" HOF calls the argument function with not only
the key/value pair, but actually *two* (in this case) pieces of data
that would in Scheme or Lisp normally be closed-over lexicals. [Two,
since otherwise the caller would have to allocate some memory to pack
them into, to get a single handle.]

Note that with a lot of hackery on the cookie (i.e., effectively
making the cookie be a dynamically-allocated "environment" frame)
you *can* even get the effect of nested closures or closures over
larger numbers of variables, but it's ugly.


-Rob

-----
Rob Warnock, PP-ASEL-IA <rp...@rpw3.org>
627 26th Avenue <URL:http://www.rpw3.org/>
San Mateo, CA 94403 (650)572-2607

Software Scavenger

unread,
Sep 10, 2002, 1:19:45 PM9/10/02
to
Oleg <oleg_i...@myrealbox.com> wrote in message news:<alkbsd$pvo$1...@newsmaster.cc.columbia.edu>...

> let silly_loop ?(increment = 1) ?(final_char = '\000') s =

I'm curious to know what do-combinations would look like in ocaml.
It works like this in lisp:

(do-combinations (a b c) '(1 2 3 4)
(print (list a b c)))
and the output is:
(1 2 3)
(1 2 4)
(1 3 4)
(2 3 4)

You can give it any number of symbols, i.e. K, e.g. K is 3 above and
the symbols are a, b, and c, and it iterates though all combinations
of N things taken K at a time. The '(1 2 3 4) are the N things, with
N being 4.

I assume you can implement do-combinations in ocaml easily, but I'm
curious to see what it would look like.

Brian Palmer

unread,
Sep 10, 2002, 1:49:10 PM9/10/02
to
Joe Marshall <j...@ccs.neu.edu> writes:

> Gee. Without all those parethesis in the way Oleg's version is
> *much* more readable. (Although it could use a few more curly
> braces and perhaps a dollar sign or two.)

hey, perl should be pretty good at this sort of thing.
(And, incidentally, I think the more explicit solution avoids an
annoying "gotcha"; almost every time I
see a loop that has two iterating constructs, I think it's nested,
rather than parallel loops)

sub silly_loop {
my ($increment, $final,$sum,$charbag);
($_,$increment,$final) = (shift,(shift or 1),shift);

s/^(.*?)\Q$final\E.*/$1/ if defined($final);

while (scalar(/(.)/g)) {
$sum += (pos()-1)*$increment;
$charbag .= $1;
}
return ($charbag,$sum,(pos||length)*$increment);
}

--
If you want divine justice, die.
-- Nick Seldon

Nils Goesche

unread,
Sep 10, 2002, 1:51:36 PM9/10/02
to
Joe Marshall <j...@ccs.neu.edu> writes:

> Oleg <oleg_i...@myrealbox.com> writes:
>
> > let silly_loop ?(increment = 1) ?(final_char = '\000') s =
> > let sum = ref 0 and i = ref 0 and char_bag = ref [] in
> > let _ = try while true do
> > char_bag := s.[!i] :: !char_bag;
> > sum := !sum + !i;
> > if List.hd !char_bag = final_char then raise Exit;
> > i := !i + increment;
> > done
> > with _ -> () in (!char_bag, !sum, !i);;

> Gee. Without all those parethesis in the way Oleg's version is


> *much* more readable. (Although it could use a few more curly
> braces and perhaps a dollar sign or two.)

And it solves the wrong problem. The /real/ problem is how to do

let loop ?? = ???;;

Or... OCaml has a keyword `lazy'. How would you implement it if it
wasn't already there? (With Lisp macros you could). Same with
`while', or `for'. Or make a repeat...until, which isn't already
there, IIRC.

Regards,
--
Nils Goesche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x0655CFA0

Oleg

unread,
Sep 10, 2002, 1:57:46 PM9/10/02
to
Software Scavenger wrote:

I understand that do-combinations is not defined in CL (at least LispWorks
environment seems to tell me so). If I were to implement it in O'Caml, it
would have the type:

val do_combinations: int -> 'a list -> 'a list list

i.e. it would take a list (of any type of variable), and integer (K = 3 in
your case) and return a list of lists (of that type), and I would use it
like this:

do_combinations 3 [1; 2; 3; 4]

which sould return
[[1; 2; 3]; [1; 2; 4]; [1; 3; 4]; [2; 3; 4]]

or

do_combinations 3 ["eins"; "zwei"; "drei"; "vier"]

which should return
[["eins"; "zwei"; "drei"]; ["eins"; "zwei"; "vier"]; ["eins"; "drei";
"vier"]; ["zwei"; "drei"; "vier"]]

(type-safe polymorphism)

If you wanted to pretty-print the result, you could use "iter" HOF defined
in List module.

Cheers
Oleg

P.S. If you still want me to implement do_combinations in O'Caml, give me a
Lisp implementation (I don't want to think of an algorithm for it)

Nils Goesche

unread,
Sep 10, 2002, 2:10:01 PM9/10/02
to
Oleg <oleg_i...@myrealbox.com> writes:

> Software Scavenger wrote:
>
> > (do-combinations (a b c) '(1 2 3 4)
> > (print (list a b c)))

> I understand that do-combinations is not defined in CL (at least LispWorks

> environment seems to tell me so). If I were to implement it in O'Caml, it
> would have the type:
>
> val do_combinations: int -> 'a list -> 'a list list

No, that's not the point. The point is that you can write

(do-combinations (a b c) some-list
<BODY>)

and then the code in BODY is called repeatedly with A, B and C bound
to the values of a ``combination''. To do that with higher order
functions, you'd have to write something like

(do-combinations (lambda (a b c)
<BODY>)
some-list)

and you write do-combinations as a macro iff you don't want to do
that.

Oleg

unread,
Sep 10, 2002, 2:23:25 PM9/10/02
to
Nils Goesche wrote:

> Oleg <oleg_i...@myrealbox.com> writes:
>
>> Software Scavenger wrote:
>>
>> > (do-combinations (a b c) '(1 2 3 4)
>> > (print (list a b c)))
>
>> I understand that do-combinations is not defined in CL (at least
>> LispWorks environment seems to tell me so). If I were to implement it in
>> O'Caml, it would have the type:
>>
>> val do_combinations: int -> 'a list -> 'a list list
>
> No, that's not the point. The point is that you can write
>
> (do-combinations (a b c) some-list
> <BODY>)
>
> and then the code in BODY is called repeatedly with A, B and C bound
> to the values of a ``combination''. To do that with higher order
> functions, you'd have to write something like
>
> (do-combinations (lambda (a b c)
> <BODY>)
> some-list)

More precisely, in O'Caml you would do

List.iter print_int_list (do_combinations 3 [1; 2; 3; 4])

What's wrong with that?

Now let's see that "do_combinations" definition! And I'll try to show how
much easier it is to define it in O'Caml (if that is the case).

Cheers,
Oleg

Marco Antoniotti

unread,
Sep 10, 2002, 2:26:14 PM9/10/02
to

Immanuel Litzroth <imma...@enfocus.be> writes:

Isn't this something alike the earliest "Aspect Oriented Programming"
work done by Kiczales in Common Lisp (or am I missing something?)

Nils Goesche

unread,
Sep 10, 2002, 2:48:38 PM9/10/02
to
Oleg <oleg_i...@myrealbox.com> writes:

> Nils Goesche wrote:
>
> > The point is that you can write
> >
> > (do-combinations (a b c) some-list
> > <BODY>)
> >
> > and then the code in BODY is called repeatedly with A, B and C bound
> > to the values of a ``combination''. To do that with higher order
> > functions, you'd have to write something like
> >
> > (do-combinations (lambda (a b c)
> > <BODY>)
> > some-list)
>
> More precisely, in O'Caml you would do
>
> List.iter print_int_list (do_combinations 3 [1; 2; 3; 4])
>
> What's wrong with that?
>
> Now let's see that "do_combinations" definition! And I'll try to show how
> much easier it is to define it in O'Caml (if that is the case).

You don't get it. The macro DO-COMBINATIONS does /not/ cons up a list
of lists. It repeatedly executes some lines of code with A, B and C
bound to some values that depend on SOME-LIST. Now read what I wrote
again.

Oleg

unread,
Sep 10, 2002, 2:52:33 PM9/10/02
to
Nils Goesche wrote:

> Joe Marshall <j...@ccs.neu.edu> writes:
>
>> Oleg <oleg_i...@myrealbox.com> writes:
>>
>> > let silly_loop ?(increment = 1) ?(final_char = '\000') s =
>> > let sum = ref 0 and i = ref 0 and char_bag = ref [] in
>> > let _ = try while true do
>> > char_bag := s.[!i] :: !char_bag;
>> > sum := !sum + !i;
>> > if List.hd !char_bag = final_char then raise Exit;
>> > i := !i + increment;
>> > done
>> > with _ -> () in (!char_bag, !sum, !i);;
>
>> Gee. Without all those parethesis in the way Oleg's version is
>> *much* more readable. (Although it could use a few more curly
>> braces and perhaps a dollar sign or two.)
>
> And it solves the wrong problem. The /real/ problem is how to do
>
> let loop ?? = ???;;

If the example Matthew Danish posted was pseudocode and needed a "loop"
macro defined first to become valid CL code, then why [in hell] would I
need a "loop" macro in O'Caml if I can implement silly_loop as easily in
_valid_ O'Caml as in Lisp pseudocode?



> Or... OCaml has a keyword `lazy'. How would you implement it if it
> wasn't already there?

You can't add keywords to the language AFAIK. I doubt that it's necessary
to have a special keyword to define lazy data types.

> (With Lisp macros you could).

In C++ too, while you can't add keywords, you can overload ordinary
operators in such a way that a team of NSA experts will not be able to
decipher your smallish program. Is that the goal?

> Same with
> `while', or `for'. Or make a repeat...until, which isn't already
> there, IIRC.

IME do {} while(...); in C++ was almost always poor design. It's not in
O'Caml for a reason.

I already posted "loop2" implementation in this thread. Other things you
mention could be implemented similarly. Note that the body of

for i = x to y do
(* ...body ... *)
done

is essentially a function of type int -> unit.

Cheers,
Oleg

Stephen J. Bevan

unread,
Sep 10, 2002, 2:56:03 PM9/10/02
to
Matthew Danish <mda...@andrew.cmu.edu> writes:
> Considering that Common Lisp can also express the same higher-order
> function, perhaps you should consider why the LOOP macro is used.

Presumably because some (many?) people find that it better expresses
a solution to their problem. Reasonable people can disagree about
whether it goes too far or alternately goes far enough.


> If you want to have some fun, why not write a nice higher-order function
> to do:
>
> (defun silly-loop (string &optional (increment 1) (final-char nil))
> (loop for n from 0 by increment
> for char across string
> until (eql char final-char)
> collect char into char-bag
> sum n into sum
> finally (return (values char-bag sum n))))
>
> Try to make it half as readable. And as efficient.

I'm not sure whether the following qualifies as being half as readable,
the efficiency would depend on whether the compiler will inline
the higher order function and I've ignored the optionallity of some of
the arguments, so with those proviso's here's some SML (since I would
use loop in Common Lisp) :-

fun sillyLoop (string, increment, finalChar) =
stringFoldr (([], 0, 0), string)
(fn ((charBag, sum, n), char, next) =>
if char = finalChar
then (charBag, sum, n)
else next (char::charBag, sum+n, n+increment))

This relies on the following auxillary (higher-order) function :-

fun stringFoldr (z, s) f =
let
val l = String.size s;
fun loop i z =
if i = l
then z
else f (z, String.sub (s, i), loop (i+1))
in
loop 0 z
end

This isn't part of SML but it is in my personal collection of string
utility functions.

Oleg

unread,
Sep 10, 2002, 3:11:57 PM9/10/02
to
Nils Goesche wrote:

Perhaps I'm not expressing myself very clearly. do_combinations is not
equivalent to DO-COMBINATIONS. I should have named it make_combinations
(and we'll call it that henceforth to avoid confusion)

You can define do_combinations _function_ in O'Caml that is similar to
DO-COMBINATIONS macro in Lisp:

val do_combinations: int -> 'a list -> ('a list -> unit) -> unit

and use it like this:

do_combinations 3 [1; 2; 3; 4] print_int_list

which would print


1 2 3
1 2 4
1 3 4
2 3 4

with appropriately defined print_int_list [1]. No need for macros.

Oleg

[1] let print_int_list lst = List.iter print_int lst; print_newline()

Nils Goesche

unread,
Sep 10, 2002, 3:15:05 PM9/10/02
to
Oleg <oleg_i...@myrealbox.com> writes:

> Nils Goesche wrote:
>
> > And it solves the wrong problem. The /real/ problem is how to do
> >
> > let loop ?? = ???;;
>
> If the example Matthew Danish posted was pseudocode and needed a "loop"
> macro defined first to become valid CL code, then why [in hell] would I
> need a "loop" macro in O'Caml if I can implement silly_loop as easily in
> _valid_ O'Caml as in Lisp pseudocode?

LOOP wasn't always part of Lisp. People wrote it as a macro. It
still is a macro, only that it is part of the ANSI standard, now.
You've been asking for examples for what you can do with macros. LOOP
itself is such an example. Not what you can do with LOOP, but LOOP
itself. And so is the whole of CLOS. When it was invented, people
added it to Lisp as a bunch of macros.

> > Or... OCaml has a keyword `lazy'. How would you implement it if it
> > wasn't already there?
>
> You can't add keywords to the language AFAIK. I doubt that it's
> necessary to have a special keyword to define lazy data types.

The point is that lazy <FOO> defers the evaluation of the expression
<FOO>. `lazy' cannot be a function because (as OCaml and Lisp are
strict) the arguments to a function call are always evaluated before
the function is entered. With macros you can do that (and other
things). lazy is a keyword in OCaml /precisely/ because people might
want it and you can't add it to the language if it isn't already
there. Lisp doesn't have LAZY but you can add it when you want it,
see PAIP, for instance (I think it's called DELAY there). And doing
that is very easy, whereas using the CamlP4 monster is not.

> > (With Lisp macros you could).
>
> In C++ too, while you can't add keywords, you can overload ordinary
> operators in such a way that a team of NSA experts will not be able to
> decipher your smallish program. Is that the goal?

Guess.

> > Same with `while', or `for'. Or make a repeat...until, which
> > isn't already there, IIRC.
>
> IME do {} while(...); in C++ was almost always poor design. It's not in
> O'Caml for a reason.

It is true that you don't need it very often. But in some situations
it is exactly the right thing and it not using it would be silly. In
Lisp, you could easily add it to the language (but it is already a
simple special case of LOOP).

> I already posted "loop2" implementation in this thread. Other things you
> mention could be implemented similarly. Note that the body of
>
> for i = x to y do
> (* ...body ... *)
> done
>
> is essentially a function of type int -> unit.

That doesn't matter. Note that all you're saying is that OCaml is
Turing-complete, which nobody denies, anyway.

Erik Naggum

unread,
Sep 10, 2002, 3:17:16 PM9/10/02
to
* Oleg <oleg_i...@myrealbox.com>

| Perhaps I'm not expressing myself very clearly.

You are expressing yourself very clearly. You make it exceptionally clear
that you understand exactly zilch of what other people are telling you.

--
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.

Oleg

unread,
Sep 10, 2002, 3:24:42 PM9/10/02
to
Erik Naggum wrote:

> * Oleg <oleg_i...@myrealbox.com>
> | Perhaps I'm not expressing myself very clearly.
>
> You are expressing yourself very clearly. You make it exceptionally
> clear that you understand exactly zilch of what other people are telling
> you.

Erik, do me (and everyone) a favor, add me to your killfile. I don't like
you for personal reasons, and let's leave it at that.

Oleg

Erik Naggum

unread,
Sep 10, 2002, 3:29:09 PM9/10/02
to
* Oleg <oleg_i...@myrealbox.com>

| Erik, do me (and everyone) a favor, add me to your killfile. I don't like
| you for personal reasons, and let's leave it at that.

Your irrationality and your hatred have both been noted. Thank you for your
candor. Few people so readily admit to have such deep personal problems.

Nils Goesche

unread,
Sep 10, 2002, 3:32:53 PM9/10/02
to
Oleg <oleg_i...@myrealbox.com> writes:

> Nils Goesche wrote:
>
> > Oleg <oleg_i...@myrealbox.com> writes:
> >
> >> Nils Goesche wrote:
> >>
> >> > The point is that you can write
> >> >
> >> > (do-combinations (a b c) some-list
> >> > <BODY>)
> >> >
> >> > and then the code in BODY is called repeatedly with A, B and C bound
> >> > to the values of a ``combination''. To do that with higher order
> >> > functions, you'd have to write something like
> >> >
> >> > (do-combinations (lambda (a b c)
> >> > <BODY>)
> >> > some-list)
> >>
> >> More precisely, in O'Caml you would do
> >>
> >> List.iter print_int_list (do_combinations 3 [1; 2; 3; 4])
> >>
> >> What's wrong with that?

> > You don't get it. The macro DO-COMBINATIONS does /not/ cons up a list


> > of lists. It repeatedly executes some lines of code with A, B and C
> > bound to some values that depend on SOME-LIST. Now read what I wrote
> > again.
>
> Perhaps I'm not expressing myself very clearly. do_combinations is not
> equivalent to DO-COMBINATIONS. I should have named it make_combinations
> (and we'll call it that henceforth to avoid confusion)
>
> You can define do_combinations _function_ in O'Caml that is similar to
> DO-COMBINATIONS macro in Lisp:
>
> val do_combinations: int -> 'a list -> ('a list -> unit) -> unit
>
> and use it like this:
>
> do_combinations 3 [1; 2; 3; 4] print_int_list

You could do that in Lisp without macros, too; then, you'd have to
call DO-COMBINATIONS as

(do-combinations 3 some-list (lambda (combi-list)
blablabla))

The point is, you write the macro if you don't /want/ to call it that
way. First, what I want is having A B C bound to the values in the
combi-list, and no consing: I want to pass a function with 3
arguments.

(do-combinations 3 some-list (lambda (a b c)
blablabla))

Then, do-combinations should be smart enough to count the number of
args itself:

(do-combinations some-list (lambda (a b c)
blabla))

But I want even more: Having to write lambda all the time here is just
silly. So, I want

(do-combinations some-list (a b c)
blabla)

where blabla might be

(foo a b)
(bar b c)
(zap c a)

or whatever. If you don't /have/ macros, you might say my desire to
do it that way is unreasonable. But the fact is, Lisp /does/ have
macros and I /can/ do it that way whenever I want.

>
> which would print
> 1 2 3
> 1 2 4
> 1 3 4
> 2 3 4
>
> with appropriately defined print_int_list [1]. No need for macros.
>
> Oleg
>
> [1] let print_int_list lst = List.iter print_int lst; print_newline()

To come closer to our example, you'd pass an anonymous function.

Christopher Browne

unread,
Sep 10, 2002, 3:35:44 PM9/10/02
to
In the last exciting episode, Oleg <oleg_i...@myrealbox.com> wrote::

> Nils Goesche wrote:
>
>> Oleg <oleg_i...@myrealbox.com> writes:
>>
>>> Software Scavenger wrote:
>>>
>>> > (do-combinations (a b c) '(1 2 3 4)
>>> > (print (list a b c)))
>>
>>> I understand that do-combinations is not defined in CL (at least
>>> LispWorks environment seems to tell me so). If I were to implement it in
>>> O'Caml, it would have the type:
>>>
>>> val do_combinations: int -> 'a list -> 'a list list
>>
>> No, that's not the point. The point is that you can write
>>
>> (do-combinations (a b c) some-list
>> <BODY>)
>>
>> and then the code in BODY is called repeatedly with A, B and C bound
>> to the values of a ``combination''. To do that with higher order
>> functions, you'd have to write something like
>>
>> (do-combinations (lambda (a b c)
>> <BODY>)
>> some-list)
>
> More precisely, in O'Caml you would do
>
> List.iter print_int_list (do_combinations 3 [1; 2; 3; 4])
>
> What's wrong with that?

What's wrong with that is that you have it "inside-out."

The point of the exercise is to write code that might look something
like:

with-combinations (a, b, c) of [ 1; 2; 3; 4] do
do_this(a, b, c);
do_that(a, b, c);
do_something_else(a, b, c);
enddo;

The "HOF way" of doing this would be to have something like

let dostuff (a, b, c) =
do_this (a, b, c);
do_that (a, b, c);
do_something_else (a, b, c);

And then do:

List.iter dostuff (do_combinations 3 [1; 2; 3; 4])

But the whole point is to NOT need to create the extra function,
dostuff(a,b,c), when it's only being used once.

There's not any fundamental "horror" at having the function; the point
is that with Lisp, you can create macros so that this sort of thing
isn't necessary.

It is Really Useful when working with things where there is some sort
of "protocol" surrounding the use of something.

For instance:

When you work with a file, starting with OPEN, and ending with CLOSE,
it's nice to hide that all inside.

Your code looks like:

(with-open-file (s filename other-parms-controlling-opening)
(do this with s)
(do that with s)
(do something else with s))

The OPEN and CLOSE are hidden; you never need to worry about them.

And you can embed this inside your code.

You _don't_ have to split things up artificially into extra functions
just because you're using this.

You _don't_ have to create:

(defun do-stuff (s more-args)
(do this with s)
(do that with s)
(do something else with s))

The reason why it's Rather Bad to need to create the extra function is
that this whole thing might be embedded in some other lexical state. It's not just:

(with-open-file (s filename other-parms-controlling-opening)
(do this with s)
(do that with s)
(do something else with s))

It's more like:

(defun foo (h1 h2 h3)
(let ((a (+ 1 h3))
(b 2))
(with-open-file (s filename other-parms-controlling-opening)
(do this with s a)
(do that with s b h1)
(do something else with s a b h2))))

By having the macro expand in-place, there's no need to name extra
functions, no need to expressly create an extra
"let/labels/flabels/..." environment in order to create extra
functions.

No such "muss and fuss." The macro system expands the structure
looking like (with-open-file args &body) into the set of code that
manages the file. It may _create_ a let or two. It may call some
functions. I don't need to care about those details; I just write
code.
--
(reverse (concatenate 'string "moc.enworbbc@" "enworbbc"))
http://cbbrowne.com/info/lisp.html
"We believe Windows 95 is a walking antitrust violation"
-- Bryan Sparks

Tim Bradshaw

unread,
Sep 10, 2002, 3:38:49 PM9/10/02
to
* oleg inconnu wrote:

> You can define do_combinations _function_ in O'Caml that is similar to
> DO-COMBINATIONS macro in Lisp:

> val do_combinations: int -> 'a list -> ('a list -> unit) -> unit

This is a fairly common implementation technique for a class of macros
in Lisp, too. For a typical WITH-x macro you define a function:

(call-with-x function arg arg ...)

which arranges to set up whatever the x is (maybe an open file) and
then to do the desetup at the end.

Then the macro definition is very simple:

(defmacro with-x ((arg ...) &body code)
`(let ((.fn. #'(lambda (arg ...) ,@code)))
(declare (dynamic-extent .fn.))
(funcall .fn. ...)))

While Lisp people clearly think that the (with-x (...) ...) form is
much easier to read, it's probably arguable that the CALL-WITH-x form
is OK, too. Certainly if Lisp had a less-verbose way of doing
anonymous functions it would probably be even more common - say
(call-with-x [(y) ...] ...) or something (where [(x) ...] means
(lambda (x) ...)).

DO-COMBINATIONS is a classic WITH-x macro in this sense.

But what all these WITH-x macros have in common is that they don't
actually do any (or much) syntactic rearrangement. Macros which *do*
do such rearrangement can't be written this way - you have to do
things to the body of the macro to produce code to be executed. It's
rather hard to give small examples of these macros, because, by
definition, they do more work.

I guess one small example would be one of the many HTML-generating
macros:

(with-html-output (s)
(:html
(:head (:title "foo"))
(:body
(:h1 "foo")
...)))

Even though this is a WITH-x macro, the body of this macro isn't Lisp
code at all, it's stylized HTML with possibly interleaved Lisp code.
The macro is in fact a little compiler which takes this `code' and
compiles it into Lisp.

I kind of suspect that I'm preaching to a congregation which is
divided here: the Lisp people are already converted and are getting
bored, and the O'Caml people will never be converted because `HOFs are
all you need' and they will never understand why macros are useful.

--tim

Nils Goesche

unread,
Sep 10, 2002, 3:52:38 PM9/10/02
to
Tim Bradshaw <t...@cley.com> writes:

> I kind of suspect that I'm preaching to a congregation which is
> divided here: the Lisp people are already converted and are getting
> bored, and the O'Caml people will never be converted because `HOFs are
> all you need' and they will never understand why macros are useful.

Some of them do understand why macros are useful. That's why they
invented CamlP4 for a substitute. When I still used OCaml, I already
knew some Lisp and felt the need for macros when I became more fluent
in OCaml. So I learned to use CamlP4. But using it was so awkward
that I finally thought ``WTF am I doing here??'' and returned to Lisp.

(The type checker was another reason. Ever tried to define an
Y-combinator in OCaml or SML? Or missed PRINT?)

Oleg

unread,
Sep 10, 2002, 4:35:35 PM9/10/02
to
Nils Goesche wrote:

> Tim Bradshaw <t...@cley.com> writes:
>
>> I kind of suspect that I'm preaching to a congregation which is
>> divided here: the Lisp people are already converted and are getting
>> bored, and the O'Caml people will never be converted because `HOFs are
>> all you need' and they will never understand why macros are useful.
>
> Some of them do understand why macros are useful. That's why they
> invented CamlP4 for a substitute. When I still used OCaml, I already
> knew some Lisp and felt the need for macros when I became more fluent
> in OCaml. So I learned to use CamlP4. But using it was so awkward
> that I finally thought ``WTF am I doing here??'' and returned to Lisp.

I'm positive that a greater percentage of serious O'Caml users know Lisp
well than vice versa. Guys who created O'Caml, like Xavier Leroy et. al.
certainly were Lisp experts. So it's not the Lisp people who are
"converted".

As to Camlp4, I don't need it and I don't use it. You make it sound like
it's necessary.

> (The type checker was another reason.

The type checker is there for a reason: one is execution speed, another
reason is reliability. While a type checker can never guarantee that your
program will do what you wanted, it removes a *great* deal of bugs: in C++,
I would frequently have this bug when I divide one int by another and treat
the result as a float. That's a very nasty type of bug, especially in any
kind of scientific/numeric application. Lisp is such an extreme case that
I'm surprised people are surprised that Lisp isn't used at JPL [1]. It
wouldn't even prevent you from dividing an int by a string in some branch
of code!

Oleg

[1]
http://groups.google.com/groups?selm=gat-1902021257120001%40eglaptop.jpl.nasa.gov&output=gplain

Stephen J. Bevan

unread,
Sep 10, 2002, 4:53:55 PM9/10/02
to
Christopher Browne <cbbr...@acm.org> writes:
> When you work with a file, starting with OPEN, and ending with CLOSE,
> it's nice to hide that all inside.
>
> Your code looks like:
>
> (with-open-file (s filename other-parms-controlling-opening)
> (do this with s)
> (do that with s)
> (do something else with s))
>
> The OPEN and CLOSE are hidden; you never need to worry about them.

I think do-combinations example I snipped is a good one for showing
how something can be done with macros that it is not easy to do using
higher order functions (modulo arguments about SCC that can remove the
list creation from the HOF version). However, here with
with-open-file you've strayed into territory which it is easy to do
with higher order functions and not even particularly onerous in any
language with higher order functions.

> (defun foo (h1 h2 h3)
> (let ((a (+ 1 h3))
> (b 2))
> (with-open-file (s filename other-parms-controlling-opening)
> (do this with s a)
> (do that with s b h1)
> (do something else with s a b h2))))
>
> By having the macro expand in-place, there's no need to name extra
> functions, no need to expressly create an extra
> "let/labels/flabels/..." environment in order to create extra
> functions.

Does the ... cover lambda :-

(defun foo (h1 h2 h3)
(let ((a (+ 1 h3))
(b 2))

(with-open-file filename other-parms-controlling-opening
(lambda (s)


(do this with s a)
(do that with s b h1)
(do something else with s a b h2))))

I don't find this any worse than the macro version myself for this
particular example (one extra indentation, possible closure creation).
For smaller examples, a more concise notation for lambda would be
helpful, and with macros one is free to create it :-)

Christopher Browne

unread,
Sep 10, 2002, 4:57:36 PM9/10/02
to
Centuries ago, Nostradamus foresaw when Nils Goesche <car...@cartan.de> would write:
> (The type checker was another reason. Ever tried to define an
> Y-combinator in OCaml or SML? Or missed PRINT?)

I obviously need to read the Little Schemer and successor again. I
still don't "get" why one would really _care_ about the Y-combinator.
--
(reverse (concatenate 'string "gro.gultn@" "enworbbc"))
http://www3.sympatico.ca/cbbrowne/x.html
If one synchronized swimmer drowns, do the rest have to drown too?

Nils Goesche

unread,
Sep 10, 2002, 5:01:49 PM9/10/02
to
Oleg <oleg_i...@myrealbox.com> writes:

> Nils Goesche wrote:
>
> > Tim Bradshaw <t...@cley.com> writes:
> >
> >> I kind of suspect that I'm preaching to a congregation which is
> >> divided here: the Lisp people are already converted and are getting
> >> bored, and the O'Caml people will never be converted because `HOFs are
> >> all you need' and they will never understand why macros are useful.
> >
> > Some of them do understand why macros are useful. That's why they
> > invented CamlP4 for a substitute. When I still used OCaml, I already
> > knew some Lisp and felt the need for macros when I became more fluent
> > in OCaml. So I learned to use CamlP4. But using it was so awkward
> > that I finally thought ``WTF am I doing here??'' and returned to Lisp.
>
> I'm positive that a greater percentage of serious O'Caml users know Lisp
> well than vice versa. Guys who created O'Caml, like Xavier Leroy et. al.
> certainly were Lisp experts. So it's not the Lisp people who are
> "converted".

I don't see the point here. Yes, I am rather sure that only a Lisp
expert could have come up with the idea to write CamlP4.

> As to Camlp4, I don't need it and I don't use it. You make it sound
> like it's necessary.

Well, what /is/ necessary? I /felt/ that it's necessary because I am
used to having the power macros give me. Obviously some OCaml man
felt so, too. In comp.lang.c and comp.programming you can find people
who think that all the stuff in C++ or higher level languages is
unnecessary. And the C++ freaks all think that closures are
unnecessary, as well as garbage collection or multi-methods.

To see the `necessity' of such things, you have to work with them
until you're used enough to them to see how they can be useful to
you. You obviously haven't worked much with macros yet, so you don't
see the point in using them. It takes a while.

> > (The type checker was another reason.
>
> The type checker is there for a reason:

Believe me, you don't have to tell me why the Hindley-Milner types
like static typing so much. I know that. I happen to disagree, but I
don't know why I should have to explain that again in comp.lang.lisp.

> one is execution speed, another reason is reliability. While a type
> checker can never guarantee that your program will do what you
> wanted, it removes a *great* deal of bugs: in C++, I would
> frequently have this bug when I divide one int by another and treat
> the result as a float. That's a very nasty type of bug, especially
> in any kind of scientific/numeric application. Lisp is such an
> extreme case that I'm surprised people are surprised that Lisp isn't
> used at JPL [1]. It wouldn't even prevent you from dividing an int
> by a string in some branch of code!

CL-USER 22 > (/ 42 "2")

Error: In / of (42 "2") arguments should be of type NUMBER.
1 (continue) Return a value to use.
2 Supply a new second argument.
3 (abort) Return to level 0.
4 Return to top loop level 0.

Type :b for backtrace, :c <option number> to proceed, or :? for other options

CL-USER 23 : 1 >

It prevented me all right, I'd say. Lisp is not Perl.

Now, what happens if I divide two ints?

CL-USER 24 > (/ 5 3)
5/3

CL-USER 25 > (* 3 (/ 5 3))
5

Looks perfectly correct to me. Let's define the factorial function in
the usual stupid way:

CL-USER 26 > (defun fac (n)
(if (zerop n)
1
(* n (fac (1- n)))))
FAC

CL-USER 27 > (mapcar #'fac '(0 1 2 3 4))
(1 1 2 6 24)

So far, so good. Now lets feed it some bigger argument:

CL-USER 28 > (fac 50)
30414093201713378043612608166064768844377641568960512000000000000

Looks good. But wait... do you know what happens if you do the same
in OCaml?

# let fac n = if n = 0 then 1 else n * (n - 1);;
val fac : int -> int = <fun>
# fac 50;;
- : int = 2450

Ah. Interesting. And WRONG!

Seriously, I doubt that there is any general purpose programming
language that is better suited for doing mathematics than Common
Lisp. And I havent even started with complex numbers yet...

Nils Goesche

unread,
Sep 10, 2002, 5:04:56 PM9/10/02
to
Christopher Browne <cbbr...@acm.org> writes:

> Centuries ago, Nostradamus foresaw when Nils Goesche <car...@cartan.de> would write:
> > (The type checker was another reason. Ever tried to define an
> > Y-combinator in OCaml or SML? Or missed PRINT?)
>
> I obviously need to read the Little Schemer and successor again. I
> still don't "get" why one would really _care_ about the Y-combinator.

Just for the heck of it. The point is, it is /trivial/ to write it in
Lisp. It is also trivial to write an ``attempt'' in ML, but the type
checker won't let you. You first have to invent a very clever trick
to beat the type checker.

And you get into such situations very easily, especially with modules
and functors. You /know/ it works, you /know/ it is correct, only the
type checker doesn't. I don't want that anymore.

Nils Goesche

unread,
Sep 10, 2002, 5:10:15 PM9/10/02
to
Nils Goesche <car...@cartan.de> writes:

> Looks perfectly correct to me. Let's define the factorial function in
> the usual stupid way:
>
> CL-USER 26 > (defun fac (n)
> (if (zerop n)
> 1
> (* n (fac (1- n)))))
> FAC
>
> CL-USER 27 > (mapcar #'fac '(0 1 2 3 4))
> (1 1 2 6 24)
>
> So far, so good. Now lets feed it some bigger argument:
>
> CL-USER 28 > (fac 50)
> 30414093201713378043612608166064768844377641568960512000000000000
>
> Looks good. But wait... do you know what happens if you do the same
> in OCaml?
>
> # let fac n = if n = 0 then 1 else n * (n - 1);;
> val fac : int -> int = <fun>
> # fac 50;;
> - : int = 2450
>
> Ah. Interesting. And WRONG!

Darn, I suck ;-) But again:

let rec fac n = if n = 0 then 1 else n * fac (n - 1);;


val fac : int -> int = <fun>
# fac 50;;

- : int = 0

Still wrong.

Eduardo Muñoz

unread,
Sep 10, 2002, 5:11:25 PM9/10/02
to
Oleg <oleg_i...@myrealbox.com> writes:

> Nils Goesche wrote:
>

> > No, that's not the point. The point is that you can write
> >
> > (do-combinations (a b c) some-list
> > <BODY>)
> >
> > and then the code in BODY is called repeatedly with A, B and C bound
> > to the values of a ``combination''. To do that with higher order
> > functions, you'd have to write something like
> >
> > (do-combinations (lambda (a b c)
> > <BODY>)
> > some-list)
>
> More precisely, in O'Caml you would do
>
> List.iter print_int_list (do_combinations 3 [1; 2; 3; 4])
>
> What's wrong with that?

A problem that I see is that the number of
combinations may exceed you phisical memory.

As example:

(with-file-lines (line file)
(with-line-tokens (tokens line))
;; Here a string and a list are consed
do-stuff)

or

(dolist (tokens (mapcar (lambda (line) (split-line line))
(read-file file)))
;; If the file is big enough the system
;; will crash and burn
do-stuff)

or the ol' way of open file, test for eof,
read-line, etc... close file.


--

Eduardo Muñoz

Bulent Murtezaoglu

unread,
Sep 10, 2002, 5:23:41 PM9/10/02
to
>>>>> "NG" == Nils Goesche <car...@cartan.de> writes:
[...]
NG> Well, what /is/ necessary? I /felt/ that it's necessary
NG> because I am used to having the power macros give me.
NG> Obviously some OCaml man felt so, too. In comp.lang.c and
NG> comp.programming you can find people who think that all the
NG> stuff in C++ or higher level languages is unnecessary. And
NG> the C++ freaks all think that closures are unnecessary, as
NG> well as garbage collection or multi-methods. [...]

Yes this is because you are looking down as outlined in
http://www.paulgraham.com/avg.html and the C/C++ crowd is looking up.

[I'll leave the rest alone]

cheers,

BM

Stephen J. Bevan

unread,
Sep 10, 2002, 5:40:34 PM9/10/02
to
Nils Goesche <car...@cartan.de> writes:
> Seriously, I doubt that there is any general purpose programming
> language that is better suited for doing mathematics than Common
> Lisp. And I havent even started with complex numbers yet...

I don't know if you consider APL and its (ASCII based) descendants J
(http://www.jsoftware.com) and K (http://www.kx.com) to be general
purpose programming languages but they are arguably better suited to
doing mathematics.

Oleg

unread,
Sep 10, 2002, 7:53:58 PM9/10/02
to
Nils Goesche wrote:

> Oleg wrote:
>> The type checker is there for a reason:
>
> Believe me, you don't have to tell me why the Hindley-Milner types
> like static typing so much.  I know that.  I happen to disagree, but I
> don't know why I should have to explain that again in comp.lang.lisp.
>
>> one is execution speed, another reason is reliability. While a type
>> checker can never guarantee that your program will do what you

>> wanted, it removes a great deal of bugs: in C++, I would


>> frequently have this bug when I divide one int by another and treat
>> the result as a float. That's a very nasty type of bug, especially
>> in any kind of scientific/numeric application. Lisp is such an
>> extreme case that I'm surprised people are surprised that Lisp isn't
>> used at JPL [1]. It wouldn't even prevent you from dividing an int
>> by a string in some branch of code!
>
> CL-USER 22 > (/ 42 "2")
>
> Error: In / of (42 "2") arguments should be of type NUMBER.
> 1 (continue) Return a value to use.
> 2 Supply a new second argument.
> 3 (abort) Return to level 0.
> 4 Return to top loop level 0.
>
> Type :b for backtrace, :c <option number> to proceed,  or :? for other
> options
>
>
> CL-USER 23 : 1 >
>
> It prevented me all right, I'd say.  Lisp is not Perl.

Perhaps a more "advanced" example was due?

(defparameter p 1)
(defun f () (if (> p 0) (/ 4 p) (/ 3 "4")))

When your hypothetical Mars lander based on a Lisp Machine finds alien life
(or other conditions not used in debugging) and is all excited to write
home to mom, it may die while composing the message...

Oleg

Erik Naggum

unread,
Sep 10, 2002, 7:56:33 PM9/10/02
to
* Oleg <oleg_i...@myrealbox.com>

| The type checker is there for a reason: one is execution speed, another
| reason is reliability.

This is commonly believed, but in fact, a type checker introduces bugs. It
shifts the cost of a certain class of mistakes so much that the kinds of
mistakes people make in the presence of a type checker destroy their ability
to think clearly about types. Experience strongly suggests that people who
use strongly-typed languages and have compilers who produce informative
error messages when type constraints are violated, cause their programmers
to believe several idiotic ideas: (1) Type errors are important. They are
not. You would not make them if the cost of making type errors was higher.
(2) Satifsying the compiler is no longer only an inconsequential necessary
condition for a program to be correct, it becomes a sufficient condition in
the minds of those who make the first mistake. (3) Errors in programs are
separated into two kinds of vastly different nature: static errors (which the
compiler may report) and dynamic errors (which the compiler cannot find).
This false dichotomy completely warps the minds of progrrammers in these
languages: Instead of becoming fundamentally stupid errors that the compiler
should just go and fix, static errors become /more/ important than dynamic
errors, leading to serious growth of dynamic errors because programmers tend
to rely on the compiler for detection and correction of mistakes.

| While a type checker can never guarantee that your program will do what you
| wanted, it removes a *great* deal of bugs: in C++, I would frequently have
| this bug when I divide one int by another and treat the result as a float.

In a real programming language created by people who actually understand
numerical types and mathematics, dividing one integer by another does not
lose information and truncate the value to an integer if the result is not
in fact an integer. The rational number that is an exact representation of
integer division does not exist in languages where types are used to increase
execution speed -- if you were primarily occupied with execution speed, you
would not even be able to /invent/ the rational number since it may easily be
a drag on performance.

| That's a very nasty type of bug, especially in any kind of scientific/numeric
| application.

This kind of bug is a consequence of strong typing and thus must be caught
by the strongly-typed system that introduced it. It is, however, fascinating
that people who invent bug opportunities because of some elegance, according
to some religion, of doing something the wrong way, do not understand that
when they have chosen to /overcome/ the bug opportunity they have invented,
such as with type checkers, other people may have removed the bug opportunity
altogether and thus not be any worse off; they may indeed be /better/ off when
the bug opportunity has been removed. Of course, provide a user of the bug-
opportunity-ridden languages with a language where this kind of bug does not
occur and he will feel frightened and lost, filled with emotions that prevent
him from thinking and acting rationally. The simple concept of numeric type
stacks (or towers or hierarchies) does not readily register with people used
to over-specify their types, but it is also typical that they feel fear when
bereft of their security blanket a.k.a. type checker and thus shut down their
thinking. It is in fact a grave design error for integer division to return
integers when the results are not always integers, but this moronic flaw in
the language does not register with people who have narrowed their options
to that which their type system can express -- Sapir-Whorf all over again --
and hence they cannot begin to understand a fundamentally different system.

People also make the kinds of mistakes they can afford to make. Because they
know that the type checker will kick in and catch their type bugs, they allow
themselves to create type bugs to begin with by not expending the necessary
mental capacity on this kind of inhumanly intricate detail. While probably
not conscious except in the highly intelligent and introspective, when you
realize that the cost of a caught type mistake is less than the cost of being
totally anal about types when you write the code, you let the type checker
figure these things out for you. The psychology of this phenomenon is not
only glaringly obvious, it has been researched in many other areas. People
who pay attention to detail consider the cost of making mistakes higher than
the cost of correcting them for personal reasons. (This a productive use of
emotions, but one may get carried away.) Whether verbalized or not, people
/are/ consciously aware of the cost of making mistakes and breaking rules --
it is called taking risks. Risks are poorly understood because people are so
frequently told not to take them.

| Lisp is such an extreme case that I'm surprised people are surprised that
| Lisp isn't used at JPL [1].

This is mere idiotic flame bait. This doofus is clearly not posting here to
understand anything he wishes to learn but to parade his lack of mental
resources and stagnated thinking. Judgmental types tend to favor strong
typing and only one way of doing things.

| It wouldn't even prevent you from dividing an int by a string in some branch
| of code!

This is more idiotic flame bait. Experienced programmers with many years of
actual experience know that timing of the reported error is inconsequential
and there is a significant loss of real value in pretending that static bugs
are more important than dynamic bugs because some fancy type theory can find
the former. In fact, every uncaught dynamic error proves that focusing too
much on the static errors is a grave mistake.

[ Oleg, please do not respond. You are not expected to overcome your personal
problems and behave rationally in the face of fundemental criticism of your
belief system. Save us the irrationality and the hatred of your feelings. ]

Thomas F. Burdick

unread,
Sep 10, 2002, 7:57:44 PM9/10/02
to
Oleg <oleg_i...@myrealbox.com> writes:

> Perhaps a more "advanced" example was due?
>
> (defparameter p 1)
> (defun f () (if (> p 0) (/ 4 p) (/ 3 "4")))
>
> When your hypothetical Mars lander based on a Lisp Machine finds alien life
> (or other conditions not used in debugging) and is all excited to write
> home to mom, it may die while composing the message...

You do realize that type inferencing is *allowed* in Lisp, right?

home:tmp/foo.lisp:
(defparameter *p* 1)
(defun f ()
(if (> *p* 0)
(/ 4 *p*)
(/ 3 "4")))

At the CMUCL toplevel:
* (compile-file "home:tmp/foo.lisp")
Converted F.
Compiling DEFUN F:

File: /home/t/tf/tfb/tmp/foo.lisp

In: DEFUN F
(/ 3 "4")
Warning: Lisp error during constant folding:
Argument Y is not a NUMBER: "4".
Warning: This is not a (VALUES &OPTIONAL NUMBER &REST T):
"4"

Byte Compiling Top-Level Form:

Compilation unit finished.
2 warnings


#p"/home/t/tf/tfb/tmp/foo.sparcf"
T
T
*


--
/|_ .-----------------------.
,' .\ / | No to Imperialist war |
,--' _,' | Wage class war! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'

Erik Naggum

unread,
Sep 10, 2002, 8:19:44 PM9/10/02
to
* Thomas F. Burdick

| You do realize that type inferencing is *allowed* in Lisp, right?

Seriously, do you think you are talking to an intelligent person who is
interested in listening to anybody when that is the kind of problems he
comes up with? The troll detector should go off pretty loudly with such
moronic comments as you are trying to counter with facts and intelligent
communication. Trolls are not after either. They are emotional beings who
need emotional answers. The poor sap from the storngly-typed language camp
needs /reassurance/ that his incompetence at programming does not hurt him.
Give him a language without strong typing and he fears he will hurt himself,
which he will because the incredible complexity of the type system that he
needed the compiler to figure out for him has left him completely unable to
think in types on his own, like a kid who always used a calculator will not
be able to do simple arithmetic in his head. It is not that it is difficult
-- it is merely that these people have never even had to do it manually, so
they have no idea how simple it really is to those who know how to do it.

Oleg

unread,
Sep 10, 2002, 8:42:33 PM9/10/02
to
Erik Naggum wrote:

> * Oleg <oleg_i...@myrealbox.com>
> | The type checker is there for a reason: one is execution speed, another
> | reason is reliability.

[..drivel..]

> [ Oleg, please do not respond. You are not expected to overcome your
> [ personal
> problems and behave rationally in the face of fundemental criticism of
> your
> belief system. Save us the irrationality and the hatred of your
> feelings. ]

After I _politely_ ask Erik to add me to his "dreaded" killfile, he
responds to my postings *twice* and asks _me_ not to respond. Is this guy
the ultimate combination of a silly person and a socially inept masochist
or what?

Erik, I don't hate you. I just don't like you. You aren't important enough
to be hated.

You are a sad rude old man who never had a life. I know all about you. And
never, Erik, and I mean never, send me any personal mail telling me who I
should boycott [1]. In America, we don't tolerate this kind of crap,
especially from jerks like you.

Have a nice day,
Oleg

[1] Re: LISP - When you've seen it, what else can impress?
From: Erik Naggum <er...@naggum.no>
To: Oleg <oleg_i...@myrealbox.com>

/Please/ do not respond to ilias.

Oleg

unread,
Sep 10, 2002, 9:10:56 PM9/10/02
to
Thomas F. Burdick wrote:

>
> You do realize that type inferencing is allowed in Lisp, right?
>

Are you saying that type inferece in Lisp can prevent run-time type errors
or only help by giving warnings in _some_ cases? Maybe I'm mistaken, but I
don't see how the former can be the case. I will try to come up with
counter-examples if you confirm that that's in fact what you really meant.

Cheers,
Oleg

Erik Naggum

unread,
Sep 10, 2002, 10:02:36 PM9/10/02
to
* Oleg <oleg_i...@myrealbox.com>

| After I _politely_ ask Erik to add me to his "dreaded" killfile, he responds
| to my postings *twice* and asks _me_ not to respond.

The article was not for you. Deal with it, moron.

--
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.

Oleg

unread,
Sep 10, 2002, 10:23:59 PM9/10/02
to
Eduardo Muñoz wrote:

>> List.iter print_int_list (do_combinations 3 [1; 2; 3; 4])
>>
>> What's wrong with that?
>
> A problem that I see is that the number of
> combinations may exceed you phisical memory.

I think I addressed this problem here:

(message id): news:allg3g$mob$1...@newsmaster.cc.columbia.edu

You can avoid creating a list of all combinations if you define

val do_combinations: int -> 'a list -> ('a list -> unit) -> unit

OTOH it's conceivable that in some cases you might just need a list of all
combinations. Since "make_combinations" can be created using
"do_combinations" above, this is probably, in fact, the Right Way of doing
it.

Cheers
Oleg

Oleg

unread,
Sep 10, 2002, 10:24:23 PM9/10/02
to
Christopher Browne wrote:

> The "HOF way" of doing this would be to have something like
>
> let dostuff (a, b, c) =
> do_this (a, b, c);
> do_that (a, b, c);
> do_something_else (a, b, c);
>
> And then do:
>
> List.iter dostuff (do_combinations 3 [1; 2; 3; 4])

Another "HOF way" is to define:

val do_combinations: int -> 'a list -> ('a list -> unit) -> unit

See (message id): news:allg3g$mob$1...@newsmaster.cc.columbia.edu

This should probably be preferred if you don't actually need the list of
all combinations.

Cheers
Oleg


Rob Warnock

unread,
Sep 11, 2002, 12:07:46 AM9/11/02
to
Nils Goesche <car...@cartan.de> wrote:
+---------------

| Christopher Browne <cbbr...@acm.org> writes:
| > I obviously need to read the Little Schemer and successor again. I
| > still don't "get" why one would really _care_ about the Y-combinator.
|
| Just for the heck of it.
+---------------

Well, it's a *little* bit more than *that*! ;-} ;-}

Basically, it provides (one way of showing) a solid theoretical basis
for recursive functions, even in a *purely* functional (non-mutational)
world. That is, it gives you a way to talk about what CL DEFUN & LABELS
and Scheme "define" & "letrec" do [w.r.t. recursive functions, that is]
*without* assuming that they're primitive in the language(s).

But beyond that, there are actually a few somewhat-useful things
you can learn from studying it, at least once. First, having done
something like define the factorial "the hard way", with Y, most
people see that there is a *less* general but simpler way to write
*specific* recursive functions without using Y [or the built-in
recursion of DEFUN or LABELS], e.g., for factorial:

> (defun fact (n)
(flet ((aux (f n)
(if (< n 2) 1 (* n (funcall f f (1- n))))))
(aux #'aux n)))
FACT
> (fact 5)
120
> (fact 50)
30414093201713378043612608166064768844377641568960512000000000000
>

Then from that one might get the notion of a tree-walker that
passes *itself* down as one of the arguments to recursive calls.
Why? Because if you pass down the function to recurse with instead
of hard-coding it into the algorithm, you can *change* that function
at some point in the walk and the rest of the walk of that sub-tree
will automatically use the new function as the default.

Note that this is similar to but subtly different from doing the
tree walk with a CLOS generic function that dispatches based on
node type, and in fact two approaches are complimentary and can
be mixed.

In short, one might not ever actually use the formal Y-combinator
in practical coding, but having studied it might have some positive
spinoffs (maybe).

+---------------


| The point is, it is /trivial/ to write it in Lisp.

+---------------

Yup, once you've seen it and walk through it enough to really grok it.
But the *first* time's sure a bitch, i'n'it... ;-} ;-}


-Rob

-----
Rob Warnock, PP-ASEL-IA <rp...@rpw3.org>
627 26th Avenue <URL:http://www.rpw3.org/>
San Mateo, CA 94403 (650)572-2607

Christopher Browne

unread,
Sep 11, 2002, 12:45:23 AM9/11/02
to
In the last exciting episode, Oleg <oleg_i...@myrealbox.com> wrote::

Maybe you should look at the Python compiler.

It does compile time type inferencing.

It does that now. It has done that for some years now.

The notion that you could come up with "counterexamples" to prove that
the Python compiler isn't doing what it has been doing for _years and
years_ is just complete silliness.

See the EncyCMUCLopedia for more details on what the Python compiler
_does_ do.
--
(reverse (concatenate 'string "ac.notelrac.teneerf@" "454aa"))
http://www3.sympatico.ca/cbbrowne/spiritual.html
Rules of the Evil Overlord #6. "I will not gloat over my enemies'
predicament before killing them." <http://www.eviloverlord.com/>

Oleg

unread,
Sep 11, 2002, 1:44:36 AM9/11/02
to
Christopher Browne wrote:

> In the last exciting episode, Oleg <oleg_i...@myrealbox.com> wrote::
>> Thomas F. Burdick wrote:
>>> You do realize that type inferencing is allowed in Lisp, right?
>>>
>>
>> Are you saying that type inferece in Lisp can prevent run-time type
>> errors or only help by giving warnings in _some_ cases? Maybe I'm
>> mistaken, but I don't see how the former can be the case. I will try to
>> come up with counter-examples if you confirm that that's in fact what you
>> really meant.
>
> Maybe you should look at the Python compiler.
>
> It does compile time type inferencing.
>
> It does that now. It has done that for some years now.
>
> The notion that you could come up with "counterexamples" to prove that
> the Python compiler isn't doing what it has been doing for _years and
> years_ is just complete silliness.

Perhaps you weren't reading carefully. I offered to give counterexamples to
the claim that "[compile-time] type inference in Lisp (CMUCL) can prevent
run-time type errors [completely]" [1] if such a claim were made.

Oleg
[1] it does in O'Caml :-)

Joe Marshall

unread,
Sep 11, 2002, 2:26:14 AM9/11/02
to

"Oleg" <oleg_i...@myrealbox.com> wrote in message news:alm0k7$5o9$1...@newsmaster.cc.columbia.edu...

>
> Perhaps a more "advanced" example was due?
>
> (defparameter p 1)
> (defun f () (if (> p 0) (/ 4 p) (/ 3 "4")))
>
> When your hypothetical Mars lander based on a Lisp Machine finds alien life
> (or other conditions not used in debugging) and is all excited to write
> home to mom, it may die while composing the message...

Nonetheless, it did *not* divide a number by string.

Matthew Danish

unread,
Sep 11, 2002, 3:27:19 AM9/11/02
to
On Tue, Sep 10, 2002 at 03:45:32AM -0400, Oleg wrote:
> > f,g) Have you tried evaluating this, lately?: let rec f () = f;;
>
> Did you mean "let rec f () = f ()" ? - infinite loop as intended.

Nope. I meant exactly what I posted.

The equivalent being (defun f () #'f) in CL or (define (f) f) in Scheme.
It's in a similar situation to the Y-combinator with regards to the
typechecker.

--
; Matthew Danish <mda...@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."

Matthew Danish

unread,
Sep 11, 2002, 3:32:50 AM9/11/02
to
On Tue, Sep 10, 2002 at 03:32:27PM -0000, Rob Warnock wrote:
> Matthew Danish <mda...@andrew.cmu.edu> wrote:
> +---------------
> | > I personally never had much use for programs in language X that generate
> | > programs in language X, especially if language X has higher-order
> | > functions, but maybe others can't live wihtout it.
> |
> | C programmers get by without higher-order functions. (somehow)
> +---------------
>
> C supports higher-order functions. In fact, they're used quite

You are completely correct, and I neglected to mention closures.
However C function pointers are such a pain in the ass, that I regard
them as a somewhat lower form of higher-order functions :-) Due to their
painfulness, they tend to be used much less by C programmers than a
functional language programmer. Also, as you point out, they are much
less useful without closures. So in a sense, "C programmers get by
without higher-order functions" in many situations where they would be
useful.

Matthew Danish

unread,
Sep 11, 2002, 3:56:35 AM9/11/02
to
On Tue, Sep 10, 2002 at 04:35:35PM -0400, Oleg wrote:
> The type checker is there for a reason: one is execution speed, another
> reason is reliability. While a type checker can never guarantee that your
> program will do what you wanted, it removes a *great* deal of bugs: in C++,
> I would frequently have this bug when I divide one int by another and treat
> the result as a float. That's a very nasty type of bug, especially in any

Fortunately, in Lisp, dividing one integer by another results in a rational
number. While doing so in O'Caml also results in a rational number, the
answer it does result in is not so "rational" :-). int * int -> int is
somewhat of a mistake, don't you think? What is 7/4?

> kind of scientific/numeric application. Lisp is such an extreme case that

> wouldn't even prevent you from dividing an int by a string in some branch
> of code!

Material scientists tend to classify various substances into two
categories: "brittle" and "ductile". Brittle materials are relatively
strong, but when a force is applied from particular directions (or an
unusually strong force is applied) they tend to experience extreme
plastic deformation and failure. Ductile materials, on the other hand,
tend to accept far more abuse while only deforming elastically (they
return to their original shape).

In small structures, where tight specifications are needed, the
unyielding rigidity of brittle materials may prove useful.

But for large structures, or structures expected to experience
unpredictably applied forces, choosing a brittle material is
disasterous.

Did you know that all tall buildings and large bridges sway? Or that
airplane wings flex, and the skin of the fuselage can tolerate a 3 foot
crack without catastrophic failure? Why are car tires made of rubber,
instead of concrete? Surely concrete will maintain a circular shape far
better than rubber would.

I will leave as an exercise for the reader the application of this
metaphor to the current discussion.

Tim Bradshaw

unread,
Sep 11, 2002, 3:58:55 AM9/11/02
to
* oleg inconnu wrote:
> The type checker is there for a reason: one is execution speed, another
> reason is reliability. While a type checker can never guarantee that your
> program will do what you wanted, it removes a *great* deal of bugs: in C++,
> I would frequently have this bug when I divide one int by another and treat
> the result as a float. That's a very nasty type of bug, especially in any
> kind of scientific/numeric application. Lisp is such an extreme case that
> I'm surprised people are surprised that Lisp isn't used at JPL [1]. It
> wouldn't even prevent you from dividing an int by a string in some branch
> of code!

Can anyone come up with a *real-world* example of a deployed Lisp
system which has failed due to runtime type problems? Or is this all
just academic masturbation by the static type people?

--tim

Pascal Costanza

unread,
Sep 11, 2002, 4:48:55 AM9/11/02
to

Oleg wrote:
>

> The type checker is there for a reason: one is execution speed, another
> reason is reliability. While a type checker can never guarantee that your
> program will do what you wanted, it removes a *great* deal of bugs:

[...]

No, a type checker is there for _two_ reasons (speed and reliability),
and that's exactly the problem. It's not necessarily a good idea to
combine two different, sometimes even contradictory goals into a single
concept. If you do that you have to make some compromises and you never
know if these compromises are the best choices in a concrete setting.

Personally I think that type systems are not per se a bad idea, but
those I have seen are overloaded with different goals and therefore too
entangled. IMHO, it's necessary to do more fundamental research on these
issues, especially empirical studies.

Pascal

--
Pascal Costanza University of Bonn
mailto:cost...@web.de Institute of Computer Science III
http://www.pascalcostanza.de Römerstr. 164, D-53117 Bonn (Germany)

Paolo Amoroso

unread,
Sep 11, 2002, 5:01:02 AM9/11/02
to
On Mon, 09 Sep 2002 18:06:07 +0300, ilias <at_...@pontos.net> wrote:

> This request is adressed to those people which have extensive knowledge
> about different, if possible all avaiable historical and so called
> modern language.
>
> Which language should i take a look on?

Do you mean you are done with Lisp (and hopefully comp.lang.lisp)? Great!
Next stop: INTERCAL.


> Is there something, that can impress me?

Probably not.


Paolo
--
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://www.paoloamoroso.it/ency/README

Bruce Hoult

unread,
Sep 11, 2002, 6:31:18 AM9/11/02
to
In article <alml5h$jrh$1...@newsmaster.cc.columbia.edu>,
Oleg <oleg_i...@myrealbox.com> wrote:

> Perhaps you weren't reading carefully. I offered to give counterexamples to
> the claim that "[compile-time] type inference in Lisp (CMUCL) can prevent
> run-time type errors [completely]" [1] if such a claim were made.
>
> Oleg
> [1] it does in O'Caml :-)

Only because O'Caml (and other HM languages) define certain things to
*not* be type errors that most people here would in fact regard as being
type errors.

-- Bruce

Nils Goesche

unread,
Sep 11, 2002, 9:48:58 AM9/11/02
to
rp...@rpw3.org (Rob Warnock) writes:

> Nils Goesche <car...@cartan.de> wrote:
> +---------------

> | The point is, it is /trivial/ to write it in Lisp.
> +---------------
>
> Yup, once you've seen it and walk through it enough to really grok
> it.

I said trivial to /write/ :-)

> But the *first* time's sure a bitch, i'n'it... ;-} ;-}

Indeed. I didn't get it at all when I first saw it in some Scheme
code, I think. Later I met it again in some book on programming
language semantics, saw the LC formula and immediately got it, so I
went to the computer to try it out...

Nils Goesche

unread,
Sep 11, 2002, 9:59:18 AM9/11/02
to
Oleg <oleg_i...@myrealbox.com> writes:

Nobody can possibly be so stupid. You, Sir, are an ordinary troll.

Bye,

Software Scavenger

unread,
Sep 11, 2002, 10:10:08 AM9/11/02
to
Oleg <oleg_i...@myrealbox.com> wrote in message news:<allbod$jd4$1...@newsmaster.cc.columbia.edu>...

> P.S. If you still want me to implement do_combinations in O'Caml, give me a
> Lisp implementation (I don't want to think of an algorithm for it)

Here is a Common Lisp implementation of it I had posted in another
thread:

(defmacro do-combinations (syms list &rest body)
(labels ((work (syms x)
(let ((y (gensym)))
(if (cdr syms)
`(loop as (,(car syms) . ,y) on ,x
do ,(work (cdr syms) y))
`(loop as ,(car syms) in ,x do ,@body)))))
(work syms list)))

It generates some code to use nested loops. The two backquoted loop
forms are for outer and innermost levels of nesting. Do you have a
Common Lisp handy to do macroexpansion etc. to make it easier to see
how it works?

Note that unlike a typical implementation, this implementation is not
a wrapper for a do-combinations function. It's the actual algorithm,
in the macro, implemented by generating the nested loops at
macroexpansion time to do the work at runtime. So if the list of
symbols, which was (a b c) in the original example, were to have 100
symbols in it instead of 3, in a particular call to this macro, it
would generate 100 levels of nested loop. If it were desired to not
generate varying amounts of code, the more common implementation with
a function wrapped by a macro would be appropriate.

Wade Humeniuk

unread,
Sep 11, 2002, 10:14:10 AM9/11/02
to

"Oleg" <oleg_i...@myrealbox.com> wrote in message
news:alm54g$939$1...@newsmaster.cc.columbia.edu...


Nothing can prevent run-time errors (even run-time type errors, take the case of
the cosmic ray altering your RAM and changing the type or value of some data,
its outside of the compilers ability to catch), at least Common Lisp can handle
run time errors (and catch that cosmic ray error) and potentially recover from
the error (not by crashing or producing unpredictable results). Bugs and
programmer errors are inevitable but with testing (maybe you do not believe in
testing?) and a language which is error handling fortified this is less of a
problem. You can still make errors in Ocaml, right???? With Lisp if an error
is caught you can also "correct" the problem in the running image without taking
the whole system down.

Wade

Marco Antoniotti

unread,
Sep 11, 2002, 11:20:08 AM9/11/02
to

Oleg <oleg_i...@myrealbox.com> writes:

==============================================================================

datatype IlTipo = Zut of int | Gnao of int list | Mannaggia of int -> int;

fun I_generate_a_runtime_error (Zut(x)) = x + 1
| I_generate_a_runtime_error (Gnao(_)) = 42;

fun zot x = I_generate_a_runtime_error x

zot (Mannaggia (fn x => x + 1));

==============================================================================

The above will generate a runtime error in SML (a 'nonexahustive match failure'
exception).

Given that the amount of information you get out of the CMUCL Python
compiler is more or less the same that you get out of the SML one, I'd
say you have to prove that SML (or OCaml - I admit I have not tested
the above on it) will always prevent you from giving you runtime
errors.

Cheers

--
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group tel. +1 - 212 - 998 3488
715 Broadway 10th Floor fax +1 - 212 - 995 4122
New York, NY 10003, USA http://bioinformatics.cat.nyu.edu
"Hello New York! We'll do what we can!"
Bill Murray in `Ghostbusters'.

Hannah Schroeter

unread,
Sep 11, 2002, 11:58:30 AM9/11/02
to
Hello!

Marco Antoniotti <mar...@cs.nyu.edu> wrote:

>[...]


>
>==============================================================================
>
>datatype IlTipo = Zut of int | Gnao of int list | Mannaggia of int -> int;
>
>fun I_generate_a_runtime_error (Zut(x)) = x + 1
> | I_generate_a_runtime_error (Gnao(_)) = 42;
>
>fun zot x = I_generate_a_runtime_error x
>
>zot (Mannaggia (fn x => x + 1));
>
>==============================================================================
>
>The above will generate a runtime error in SML (a 'nonexahustive match failure'
>exception).

>Given that the amount of information you get out of the CMUCL Python
>compiler is more or less the same that you get out of the SML one, I'd
>say you have to prove that SML (or OCaml - I admit I have not tested
>the above on it) will always prevent you from giving you runtime
>errors.

*ML compilers (can) generate compile-time warnings on functions like
I_generate_a_runtime_error.

Kind regards,

Hannah.

J.St.

unread,
Sep 11, 2002, 12:39:15 PM9/11/02
to
"Joe Marshall" <prunes...@attbi.com> writes:

As it was already said: It's not Perl. :)

But besides: "Oleg" is not willing to be convinced of anything... or
at least accept other aspects.

Regards,
Julian

Rob Warnock

unread,
Sep 11, 2002, 12:44:21 PM9/11/02
to
Matthew Danish <mda...@andrew.cmu.edu> wrote:
+---------------
| However C function pointers are such a pain in the ass, that I regard
| them as a somewhat lower form of higher-order functions :-) Due to their
| painfulness, they tend to be used much less by C programmers than a
| functional language programmer. Also, as you point out, they are much
| less useful without closures. So in a sense, "C programmers get by
| without higher-order functions" in many situations where they would be
| useful.
+---------------

No argument.

However, it's worth also pointing out that once one has had significant
exposure to (quasi-)functional languages (CL & Scheme count here), one
may find *much* greater use of higher-order functions and perhaps even
explicit closures (manully-managed, or with a small auxiliary lib) popping
up in one's C code, with beneficial effects on coding time and correctness.

Heavens! I've even found myself occasionally using HOFs in *firmware*!! ;-}

Erann Gat

unread,
Sep 11, 2002, 12:03:51 PM9/11/02
to
In article <alll09$q9f$1...@newsmaster.cc.columbia.edu>, Oleg
<oleg_i...@myrealbox.com> wrote:

> I'm surprised people are surprised that Lisp isn't used at JPL [1]. It
> wouldn't even prevent you from dividing an int by a string in some branch
> of code!

Lisp was used at JPL for decades (and it's actually still in use in at
least one fielded application, though there's currently no active Lisp
development to my knowledge). The reason it fell out of favor had
absolutely nothing to do with typing, or any other techincal reason; it
was purely political.

Erann Gat
Principal Scientist
Jet Propulsion Laboratory
California Institute of Technology
g...@jpl.nasa.gov

Disclaimer: The views expressed in this posting are my own.

Thomas F. Burdick

unread,
Sep 11, 2002, 1:09:33 PM9/11/02
to
Erik Naggum <er...@naggum.no> writes:

> * Oleg <oleg_i...@myrealbox.com>


> | The type checker is there for a reason: one is execution speed, another
> | reason is reliability.
>

> This is commonly believed, but in fact, a type checker introduces
> bugs. It shifts the cost of a certain class of mistakes so much
> that the kinds of mistakes people make in the presence of a type
> checker destroy their ability to think clearly about types.
> Experience strongly suggests that people who use strongly-typed
> languages and have compilers who produce informative error
> messages when type constraints are violated, cause their
> programmers to believe several idiotic ideas:

This is interesting -- I've noted a similar disposition among users of
statically-typed languages (speaking statistically, of course, as
there are plenty of individuals who don't fall into any given mental
trap). I have a completely untested hypothesis on this subject, and
I'm too inexperienced with this type of language to even run a
thought-experiment on it: this mental trap is the result of having the
type inferencer complain that your program is not fully typable,
*while it is still in heavy development*. When it complains that it
can prove you've made an error, that's good, it prevents you from
doing stupid things that make for often hard-to-find bugs. When it
complains that your still largely unfinished program isn't typable,
that's inappropriate. But there may be some use (depending on the
nature of the program) in having it complain that your
production-ready program isn't typable.

The experiment I'd like to try here would be to have a Lisp compiler
that would attempt to completely type your program. If you've told it
that it's compiling code that it should be able to type, it will warn
you if it can't; otherwise it'll keep quiet. As someone with only a
small amount of experience with language systems that insist on being
able to type your programs, I don't have any stupidity alarms to go
off here; I'm curious if any Lispers who have more experience with
such systems think this could be of value.

--
/|_ .-----------------------.
,' .\ / | No to Imperialist war |
,--' _,' | Wage class war! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'

Thomas F. Burdick

unread,
Sep 11, 2002, 1:18:07 PM9/11/02
to
Oleg <oleg_i...@myrealbox.com> writes:

> After I _politely_ ask Erik to add me to his "dreaded" killfile, he

> responds to my postings *twice* and asks _me_ not to respond. Is this guy
> the ultimate combination of a silly person and a socially inept masochist
> or what?

That ain't how it works. If you don't want to converse with someone,
*you* gotta ignore *him*.

> You are a sad rude old man who never had a life. I know all about you. And
> never, Erik, and I mean never, send me any personal mail telling me who I
> should boycott [1]. In America, we don't tolerate this kind of crap,
> especially from jerks like you.

You're right, especially in the last year, there's been a huge
resurgence of fascistic thugs. It's gonna be a long, hard fight when
the west coast ports go on strike.

Thomas F. Burdick

unread,
Sep 11, 2002, 1:29:54 PM9/11/02
to
Erik Naggum <er...@naggum.no> writes:

> * Thomas F. Burdick
> | You do realize that type inferencing is *allowed* in Lisp, right?
>
> Seriously, do you think you are talking to an intelligent person who is
> interested in listening to anybody when that is the kind of problems he
> comes up with? The troll detector should go off pretty loudly with such
> moronic comments as you are trying to counter with facts and intelligent
> communication.

Hmm, I think maybe the sarcasm in the above statement got lost in the
writing. I was just using it as an excuse to point out a cool feature
of Python, not to Oleg, but to anyone reading who didn't know about it.

> Trolls are not after either. They are emotional beings who need
> emotional answers. The poor sap from the storngly-typed language
> camp needs /reassurance/ that his incompetence at programming does
> not hurt him. Give him a language without strong typing and he
> fears he will hurt himself, which he will because the incredible
> complexity of the type system that he needed the compiler to
> figure out for him has left him completely unable to think in
> types on his own, like a kid who always used a calculator will not
> be able to do simple arithmetic in his head. It is not that it is
> difficult -- it is merely that these people have never even had to
> do it manually, so they have no idea how simple it really is to
> those who know how to do it.

I know someone who went to a suburban school system, flush with money,
who used calculators in class starting in the 9th grade, and took a
lot of math in school -- his last year of high school, he took
multivariable calculus. He graduated college with a CS degree.
Recently, I was talking to him, and he was stuck analysing an
algorithm, and asked for help. I looked at what he was doing, and
within a couple minutes pointed out how he could get past where he was
stuck. He has better math skills than me (by quite a lot), but
between the low-calculator-use math classes I've taken, and the
tutoring I've done, I can do arithmetic and simple algebra in my head
very well -- which was really all this analysis needed. [I wonder how
far this parallel works]

Erann Gat

unread,
Sep 11, 2002, 1:38:29 PM9/11/02
to
In article <32406909...@naggum.no>, Erik Naggum <er...@naggum.no> wrote:

> Experienced programmers with many years of
> actual experience know that timing of the reported error is inconsequential

Though I agree with Erik's overall point, that the value of static typing
is highly overrated by its advocates, I have to disagree with this.
Catching errors at compile time can be very useful, particularly in
embedded applications where actually running the program can be very
expensive, and in some cases even dangerous.

E.

od...@sivos.rl.no

unread,
Sep 11, 2002, 2:34:37 PM9/11/02
to
Matthew Danish:


> Brittle materials are relatively strong, but when a force is applied
> from particular directions (or an unusually strong force is applied)
> they tend to experience extreme plastic deformation and failure.
> Ductile materials, on the other hand, tend to accept far more abuse
> while only deforming elastically (they return to their original
> shape).

Hmm, I am very surprised.

I once learned that a ductile material can take a lot of _plastic_
deformation before fracturing. Plastic deformation does of course mean
that it does not at all return to its original shape once its ductile
property has been exploited. Gold is a very ductile material, it can
be squeezed leaf thin without fracturing.

Brittle materials fracture with no or very little plastic flow. Their
main characteristic is that they respond to increasing load with an
elastic deformation and then fracture. In contrast, ductile materials
respond with an elastic deformation, then plastic deformation and then
finally, fracture. In general; the more plastic deformation prior to
fracture, the more ductile. (This is a bit simplified, cross sectional
area reduction during the plastic flow plays a role here)

Brittle materials being releatively strong, may be a little
far fetched. They often show relative low tensile strength. The
compressive strength may however, be an order of magnitude higher.

Brittle materials are often counted among the "hard" materials,
but hardness is a different and quite complex animal.

> In small structures, where tight specifications are needed, the
> unyielding rigidity of brittle materials may prove useful.

Rigidity (stiffness) is often a combination of elasticity and
geometry. Geometry may be more important than the material. In any
case, the Young's modulus is likely to be more important than the
ductility.


> But for large structures, or structures expected to experience
> unpredictably applied forces, choosing a brittle material is
> disasterous.

Quite a few large structures, bridges included, built in the 1800s
still stand, even those built from ordinary cast iron parts. Cast iron
(gray iron) is, as you know, not very ductile. I absolutely agree on
ductility being an important property when it comes to preventing
cracks from advancing. The key factor is high energy absorption during
plastic deformation in the front area of a propagating crack. Plastic
deformation that is, the material does not return to its original
shape.


> Did you know that all tall buildings and large bridges sway? Or that
> airplane wings flex, and the skin of the fuselage can tolerate a 3 foot
> crack without catastrophic failure?

Flexing is not (at least not directly) related to ductility. Rubber,
as in rubber tires, is flexible but not very ductile. In the mid 1950s
brittle fractures in aluminium caused the loss of at least two (Comet)
aircrafts. Brittle fractures also sent early steel ships to the sea
bed, even though they were built in mild, and supposedly ductile,
steel. Also, quite a few naval ships were lost during world war two
due to brittle fractures.

> I will leave as an exercise for the reader the application of this
> metaphor to the current discussion.

Giving Lisp illiterates like myself a hard time, right :-)

--
Odd Skjaeveland od...@sivos.rl.no

Nils Goesche

unread,
Sep 11, 2002, 2:38:43 PM9/11/02
to
t...@hurricane.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> The experiment I'd like to try here would be to have a Lisp compiler
> that would attempt to completely type your program. If you've told it
> that it's compiling code that it should be able to type, it will warn
> you if it can't; otherwise it'll keep quiet. As someone with only a
> small amount of experience with language systems that insist on being
> able to type your programs, I don't have any stupidity alarms to go
> off here; I'm curious if any Lispers who have more experience with
> such systems think this could be of value.

I think it's not going to work. A simple example would be

(defun main ()
(pprint (+ 42 (read))))

Now, to make sure there will be no type-errors, you'd have to add code
that will make sure that it will be a number that is added to 42;
however, how is the compiler supposed to decide whether your checks
are sufficient? The compiler would have to /understand/ your code. I
think you'll be quickly running into unsolvable problems like the
halting problem and friends. (I'm just guessing here, but would be
very surprised if I wasn't guessing right ;-)

The static type checkers of compilers for languages like ML aren't
perfect either. In fact, they will reject a valid program if they
can't prove it to be type safe. Those languages are designed in a
special way that makes sure that the class of programs that /can/ be
proven to be type safe by the type inference algorithm is sufficiently
large.

Regards,

Marco Antoniotti

unread,
Sep 11, 2002, 3:05:51 PM9/11/02
to

han...@schlund.de (Hannah Schroeter) writes:

Yes. I know. And the SML compiler I used does that: it generates a
*warning*. However, that is similar to the information you get from
the CMUCL Python compiler when you pass around types that are not
correct.

Again, as I said previously the best language would be CL with solid
type inferencing: CMUCL/Python comes pretty close. By switching to
*ML languages I feel I give up way too much to justify the change.

Kaz Kylheku

unread,
Sep 11, 2002, 3:11:25 PM9/11/02
to
Oleg <oleg_i...@myrealbox.com> wrote in message news:<alj0n5$pmc$1...@newsmaster.cc.columbia.edu>...
> I'm not an expert in macros, but IIRC I've seen an example of a "loop"
> macro in Lisp that was used to demonstrate their usefulness. I'm not sure I
> understand how using macros is any better than using higher-order functions
> (HOFs) though.
>
> E.g. to write a loop construct that increments its arument by 2 instead of
> 1, in O'Caml, I would write
>
> let rec loop2 start finish f =
> if finish < start then () else (f start; loop2 (start + 2) finish f)

By the way, is ``if'' a function in O'Caml?

> which is probably close to what one could do with HOFs in Lisp. No need for
> macros. Now
>
> loop2 1 9 print_int
>
> will print 13579. I guess the old saying that "if you don't know it, you
> won't miss it" probably applies to me and Lisp macros here.

What you are missing is that macros open-code; that is, generate
code in place. That code can do things like create environments in
which
bindings are established, or control the evaluation of constituent
forms.
In fact, a macro can parse the raw form which invoked it, and emit an
arbitrary translation.

What if your loop construct is to declare a loop variable, which is
visible to the constituent form? There is a big difference between
what you did above and, say:

(dotimes (i 10) (print i))

dotimes is a language feature which causes the variable i to be
visible
to the form (print i). It evaluates that form ten times in its
lexically
apparent environment, successively binding the variable i to the
values 0 through 9. Successively calling a function with the arguments
0 through 9
is not the same thing.

Higher order functions do not replace macros; they do not have the
freedom
to arbitrarily interpret the meaning of a piece of the program. They
are subject to evaluation rules which prevent access to an unevaluated
argument expression. If you call a function with the argument
i, it cannot, for instance, be interpreted as the name of a variable
to
bind. At best, i can be lazily evaluated, at the latest possible time
before the value of that parameter is required, but that is not the
same thing as having control over evaluation.

Kaz Kylheku

unread,
Sep 11, 2002, 3:16:23 PM9/11/02
to
Oleg <oleg_i...@myrealbox.com> wrote in message news:<alkbsd$pvo$1...@newsmaster.cc.columbia.edu>...
> Matthew Danish wrote:
>
> >
> > If you want to have some fun, why not write a nice higher-order function
> > to do:
> >
> > (defun silly-loop (string &optional (increment 1) (final-char nil))
> > (loop for n from 0 by increment
> > for char across string
> > until (eql char final-char)
> > collect char into char-bag
> > sum n into sum
> > finally (return (values char-bag sum n))))
> >
> > Try to make it half as readable.  And as efficient.
>
> let silly_loop ?(increment = 1) ?(final_char = '\000') s =
> let sum = ref 0 and i = ref 0 and char_bag = ref [] in
> let _ = try while true do
> char_bag := s.[!i] :: !char_bag;
> sum := !sum + !i;
> if List.hd !char_bag = final_char then raise Exit;
> i := !i + increment;
> done

In Lisp, any special form can, in principle, be implemented by a
macro. If someone took away your DO loop, you could write it from
scratch.

Suppose that the construct ``while true do ... done'' did not exist
in O'Caml. How would you implement it, such that exactly the same
syntax is supported (like the above example, for instance).
Can you do it entirely with higher order functions? I'd like
to see how.

Kaz Kylheku

unread,
Sep 11, 2002, 3:30:51 PM9/11/02
to
Oleg <oleg_i...@myrealbox.com> wrote in message news:<allbod$jd4$1...@newsmaster.cc.columbia.edu>...

> Software Scavenger wrote:
>
> > Oleg <oleg_i...@myrealbox.com> wrote in message
> > news:<alkbsd$pvo$1...@newsmaster.cc.columbia.edu>...
> >
> >> let silly_loop ?(increment = 1) ?(final_char = '\000') s =
> >
> > I'm curious to know what do-combinations would look like in ocaml.
> > It works like this in lisp:
> >
> > (do-combinations (a b c) '(1 2 3 4)
> > (print (list a b c)))
> > and the output is:
> > (1 2 3)
> > (1 2 4)
> > (1 3 4)
> > (2 3 4)

> like this:


>
> do_combinations 3 [1; 2; 3; 4]
>

> which sould return
> [[1; 2; 3]; [1; 2; 4]; [1; 3; 4]; [2; 3; 4]]

No, you don't get it. The object is not to return a list of the
combinations, but to bind some variables to each combination,
and then evaluate forms in a lexical environment in which those
bindings are visible.

Please don't change the problem specification to suit your language!

Do-combinations is in fact a control construct; a function that
returns combinations is not a control construct.

These are very different things. One trivial difference is that
you could do:

(do-combinations (a b c) '(1 2 3 4)
(when (.. some condition involving a b c)
(return)))

In other words, stop generating combinations upon encountering
some condition.

The space of combinations could be huge, so that consing up a list
and then searching through it could be intractable.

I want to see an O'Caml construct written in O'Caml which
binds the variables a b c to the combinations of 1 2 3 4,
and executes a body of arbitrary statements under those bindings.

Nils Goesche

unread,
Sep 11, 2002, 3:31:22 PM9/11/02
to
k...@ashi.footprints.net (Kaz Kylheku) writes:

> In Lisp, any special form can, in principle, be implemented by a
> macro. If someone took away your DO loop, you could write it from
> scratch.

That's because DO is in fact a macro. The special forms are rather
the exceptions to what you mean :-) See

3.1.2.1.2.1 Special Forms

in the HyperSpec, and ``special form'' in the Glossary.

You can also get a list by evaluating

(do-external-symbols (sym "CL")
(when (special-operator-p sym)
(print sym)))

Kaz Kylheku

unread,
Sep 11, 2002, 3:50:21 PM9/11/02
to
Oleg <oleg_i...@myrealbox.com> wrote in message news:<alll09$q9f$1...@newsmaster.cc.columbia.edu>...
> Nils Goesche wrote:
>
> > Tim Bradshaw <t...@cley.com> writes:
> >
> >> I kind of suspect that I'm preaching to a congregation which is
> >> divided here: the Lisp people are already converted and are getting
> >> bored, and the O'Caml people will never be converted because `HOFs are
> >> all you need' and they will never understand why macros are useful.
> >
> > Some of them do understand why macros are useful. That's why they
> > invented CamlP4 for a substitute. When I still used OCaml, I already
> > knew some Lisp and felt the need for macros when I became more fluent
> > in OCaml. So I learned to use CamlP4. But using it was so awkward
> > that I finally thought ``WTF am I doing here??'' and returned to Lisp.
>
> I'm positive that a greater percentage of serious O'Caml users know Lisp
> well than vice versa. Guys who created O'Caml, like Xavier Leroy et. al.
> certainly were Lisp experts. So it's not the Lisp people who are
> "converted".
>
> As to Camlp4, I don't need it and I don't use it. You make it sound like
> it's necessary.
>
> > (The type checker was another reason.
>
> The type checker is there for a reason: one is execution speed, another
> reason is reliability. While a type checker can never guarantee that your
Type checking does nothing for execution speed. It verifies constraints.
An optimizer can use declared or inferred type information to improve
speed. Optimizing and type checking are distinct activities.

Requiring users to declare type information is not done for safety;
it is done purely to make it easier for the language implementor
to optimize code, while making it hard for everyone else to write it.

> program will do what you wanted, it removes a *great* deal of bugs: in C++,
> I would frequently have this bug when I divide one int by another and treat
> the result as a float. That's a very nasty type of bug, especially in any
> kind of scientific/numeric application. Lisp is such an extreme case that

> I'm surprised people are surprised that Lisp isn't used at JPL [1].

Lisp doesn't have this problem; the type is deduced dynamically from
the types of the operands. Dividing two integers will produce a ratio
of the division is inexact, or else an integer. The decision is dynamic,
depending on the run-time values. It cannot be type checked in the
general case.

> wouldn't even prevent you from dividing an int by a string in some branch > of code!

Dividing an integer by a string would signal a condition. Of course, this
is not caught until it actually happens. A Lisp type checker could catch
only some statically obvious cases of this, but not every case.

Compilers for static languages *must* catch this kind of error at compile
time, because they throw away the information. Dividing an integer by
a string, if it was not diagnosed, would have completely unpredictable
results---for example, the bits representing some part of the string
object, such a pointer to its data, could be interpreted as an integer
value.

Programmers who only understand static languages think that this discarding
is necessary, and therefore static type checking is some essential thing
that every decent language must have, and therefore declarations are good
because only with declarations can everything be thoroughly checked.

But what happens is that these programmers invent second-order mechanisms
for introducing run-time typing. Things like integer type codes in structs.
For example, in the BSD operating system, a struct vnode type has
a v_type field, which can hold values like VREG (regular file),
VDIR (directory) and others. And there are explicit run-time checks to
make sure that the wrong operation isn't applied, such as trying to
readdir() on a regular file, or link() a directory, which must be
converted to -1/errno == EPERM results.

And of course, only programmer discipline ensures that the checks
are done properly and thoroughly. If you don't write the check,
you don't get the check.

If you don't have dynamic typing built into the language, programmers
will reinvent it using ad-hoc, inherently fragile programming
conventions.

Pascal Costanza

unread,
Sep 11, 2002, 4:42:13 PM9/11/02
to
Thomas F. Burdick wrote:

[...]


> This is interesting -- I've noted a similar disposition among users of
> statically-typed languages (speaking statistically, of course, as
> there are plenty of individuals who don't fall into any given mental
> trap). I have a completely untested hypothesis on this subject, and
> I'm too inexperienced with this type of language to even run a
> thought-experiment on it: this mental trap is the result of having the
> type inferencer complain that your program is not fully typable,
> *while it is still in heavy development*. When it complains that it
> can prove you've made an error, that's good, it prevents you from
> doing stupid things that make for often hard-to-find bugs. When it
> complains that your still largely unfinished program isn't typable,
> that's inappropriate. But there may be some use (depending on the
> nature of the program) in having it complain that your
> production-ready program isn't typable.

Such a thing, in fact, exists. The Eclipse IDE (http://www.eclipse.org)
includes a Java compiler that statically checks types and reports errors
(as other Java compilers), but it allows you to run the code
nonetheless, i.e. those parts that have been successfully compiled
(unlike other Java compilers/IDEs). Obviously, even users of static
languages tend to have a need for more dynamic features. (This is
another proof of Paul Graham's statement about traditional languages
heading towards Common Lisp's flexibility.)

(BTW, a Common Lisp plugin for Eclipse would be nice. ;)

> The experiment I'd like to try here would be to have a Lisp compiler
> that would attempt to completely type your program. If you've told it
> that it's compiling code that it should be able to type, it will warn
> you if it can't; otherwise it'll keep quiet. As someone with only a
> small amount of experience with language systems that insist on being
> able to type your programs, I don't have any stupidity alarms to go
> off here; I'm curious if any Lispers who have more experience with
> such systems think this could be of value.

You want to have soft typing, right? I would like that also, seems to me
to be the best compromise as of yet.

Pascal


ilias

unread,
Sep 11, 2002, 5:24:16 PM9/11/02
to
can we continue where we've stopped?

Gareth McCaughan

unread,
Sep 11, 2002, 6:23:40 PM9/11/02
to
Erik Naggum wrote:

[Oleg, about int / int -> int]


> | That's a very nasty type of bug, especially in any kind of
> | scientific/numeric application.
>

> This kind of bug is a consequence of strong typing and thus must be caught
> by the strongly-typed system that introduced it.

I think "consequence" is a bit strong. The Python language[1]
is dynamically typed, but it has the int/int -> int "feature".

It's probably true that only a static typing system can
*excuse* -- as opposed to *explain* -- making integer
division yield integers.

I should perhaps add that making int/int *not* truncate
is in the plans for Python's future. You can imagine
the backward-compatibility nightmares.

Oh, and can I put in a plea for not using "strong"
to mean "static" in this context? C is statically typed
but not strongly typed. CL is strongly typed but not
statically typed. And, in the interests of completeness:
Perl is neither strongly typed nor statically typed;
Pascal is both strongly and statically typed.


[1] Nothing to do with the Python CL compiler, of course.

--
Gareth McCaughan Gareth.M...@pobox.com
.sig under construc

Erik Naggum

unread,
Sep 11, 2002, 6:59:55 PM9/11/02
to
* Gareth McCaughan

| I should perhaps add that making int/int *not* truncate is in the plans for
| Python's future. You can imagine the backward-compatibility nightmares.

Will there be a new infix operator for the real division? I have seen //
used for this purpose, but some jerk had to use it up for comments. (Even in
C++, ;; could be used for comments.)

| Oh, and can I put in a plea for not using "strong" to mean "static" in this
| context? C is statically typed but not strongly typed. CL is strongly typed
| but not statically typed. And, in the interests of completeness: Perl is
| neither strongly typed nor statically typed; Pascal is both strongly and
| statically typed.

This is worthwhile clarification. Thanks.

--
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.

Bruce Hoult

unread,
Sep 11, 2002, 7:46:38 PM9/11/02
to
In article <a6789134.02091...@posting.google.com>,
cubic...@mailandnews.com (Software Scavenger) wrote:

Here's Dylan version for you:

define macro do-combinations
{do-combinations (?:name in ?:expression) ?:body end}
=> {for (?name in ?expression) ?body end};

{do-combinations (?:name, ?names:* in ?:expression) ?:body end}
=> {for (y = ?expression then y.tail, while: y ~== #())
let ?name = y.head;
do-combinations (?names in y.tail) ?body end
end};
end macro;

do-combinations (x,y,z in #("the", "quick", "brown", "fox", "jumps"))
format-out("%= %= %=\n", x, y, z);
end;

bruce@k7:~/programs/dylan/combinations > ./combinations
"the" "quick" "brown"
"the" "quick" "fox"
"the" "quick" "jumps"
"the" "brown" "fox"
"the" "brown" "jumps"
"the" "fox" "jumps"
"quick" "brown" "fox"
"quick" "brown" "jumps"
"quick" "fox" "jumps"
"brown" "fox" "jumps"


Dylan's for() loop doesn't have the list destructuring feature of CL's
loop macro, so I had to do that part by hand.

On the other hand, I can show you a slightly longer version that
produces optimal code not only for lists but also for strings, vectors,
hash tables etc (if the actual type is known at the point of
macro-expansion, of course).

do-combinations (x,y,z in "qwerty")
format-out("%= %= %=\n", x, y, z);
end;

bruce@k7:~/programs/dylan/combinations > ./combinations
'q' 'w' 'e'
'q' 'w' 'r'
'q' 'w' 't'
'q' 'w' 'y'
'q' 'e' 'r'
'q' 'e' 't'
'q' 'e' 'y'
'q' 'r' 't'
'q' 'r' 'y'
'q' 't' 'y'
'w' 'e' 'r'
'w' 'e' 't'
'w' 'e' 'y'
'w' 'r' 't'
'w' 'r' 'y'
'w' 't' 'y'
'e' 'r' 't'
'e' 'r' 'y'
'e' 't' 'y'
'r' 't' 'y'

Interested?

-- Bruce

It is loading more messages.
0 new messages