
Common Lisp is not secretly Scheme with bad syntax - gnosis
http://groups.google.com/group/comp.lang.lisp/msg/43090ddeeb50051c
======
Homunculiheaded
Whenever I introduce people to functional programming, I always list the
standard benefits you'll hear and then put emphasis on powerful abstraction
being the most important feature that makes fp worth learning.

Common Lisp is great because it realizes that abstraction and expressiveness
are what make fp powerful, and is smart enough to know when to drop 'purity'
in favor of these.

After spending a lot of time with Haskell and Scheme, Common Lisp feels very
non-functional, however I still feel it is the best language for
expressiveness and abstraction. Work with Scheme and Haskell enough and you'll
find yourself writing some convoluted things to maintain purity. The problem
with purity is that while it makes somethings much easier to express, there
are times when you have to stop and ask "how do I express this", I find common
lisp always gives you some way to express anything, but leaves you asking "how
can I express this better?"

~~~
kunjaan
>Work with Scheme and Haskell enough and you'll find yourself writing some
convoluted things to maintain purity.

I don't think you can lump all the Scheme languages into one umbrella and more
importantly lump Scheme and Haskell in that context.

For example, Racket has really good constructs that lets me "drop 'purity'",
control side-effects, build sequences, control the flow, build classes, manage
complexity while at the same time giving me the power to build higher levels
of abstractions, express my thoughts and reason with my program.

Reference:

0\. Racket Guide: <http://docs.racket-lang.org/guide/index.html>

1\. System Programming with Racket : <http://docs.racket-lang.org/more/>

~~~
anon_d
Racket is not a scheme.

~~~
kunjaan
Racket is a Scheme

"Racket is still a dialect of Lisp and a descendant of Scheme. The tools
developed by PLT will continue to support R5RS, R6RS, the old mzscheme
environment, Typed Scheme, and more. At the same time, instead of having to
say “PLT's main variant of Scheme,” programmers can now simply say “Racket” to
refer to the specific descendant of Scheme that powers PLT's languages and
libraries."

Reference : <http://racket-lang.org/new-name.html>

------
CountSessine
Taken from the same thread, I loved this response, from Stefan Scholl:

    
    
        >There seems to be a great deal of interest 
        >from the functional programming community 
        >in benchmarking. Is there enough interest 
        >to create a new computer language shootout 
        >that showcases more relevant/suitable tasks 
        >for FP?
    
        Does this sell books? Should I write one?

------
GrooveStomp
After reading the first paragraph, I realized that I mistook "CL" to mean
"Clojure." The comment about Common Lisp lacking tail-call-optimization being
a factor in not considering it a functional language reflects my only real
problem with Clojure so far.

Other than that, this writeup reflects what I've learned so far of Common Lisp
- it's much more of an imperative style language than it is a functional
language.

~~~
irahul
Clojure does have TCO, though you have to be explicit about it.

I use Clojure's looping constructs and list comprehensions for most of the
tasks; explicit TCO using loop/recur for problems which are best expressed
recursively.

~~~
ohyes
Sort of.

In true TCO, you optimize not only tail calls to the same function, but also
tail calls to other functions. (Think of coroutines as an application).

One way to think of a TCO is that you are turning a function call (machine
code to save your spot in the function, then a jump) into a simple jump (you
don't need to save your spot, because there is nothing left in the function
anyway).

Clojure doesn't support this (because it would be too difficult[inefficient, i
think kawa scheme and JRuby do implement it] on the JVM). I assume that the
common lisps which do support TCO, have true TCO, as they are using assembly
or interpreters.

Clojure's TCO can be seen as a special form of a loop (in fact, it is very
easy to write a macro that takes a loop-recur form and transforms it into a
common lisp style Do* loop).

~~~
swannodette
As I mention below you can get the same result with lazy-sequences and it's
_very_ efficient.

~~~
ohyes
I think that you would have to be careful with that. To my knowledge, with
lazy sequences in Clojure, the thunks are grouped into segments of 32.

This chunking is for efficiency, but it has the (sometimes) weird implication
that you ask for the first element in a sequence and it evaluates that first
element, and the next 31 elements as well. This is troublesome if you attempt
to use side effects.

(Mr. Fogus has a nice writeup (and workaround) of this phenomena here:
[http://blog.fogus.me/2010/01/22/de-chunkifying-sequences-
in-...](http://blog.fogus.me/2010/01/22/de-chunkifying-sequences-in-clojure/))

I have to admit, I am not quite getting my head around how using a lazy
sequence to the same effect would work (ignoring the chunking issue). I see
how they are similar, a lazy sequence is just a flattened trampoline. Could
you maybe pastebin or lisppaste an example?

Anyway, I guess the point I was trying to make was not that it is impossible
to do these things, but that TCO is a compiler level optimization of the
function calling convention (manipulating the stack), and although Clojure has
'tail calls,' it can't really be called TCO in the true sense of the word.
(Which is OK, as you said, there are other ways to do this sort of stuff).

~~~
swannodette
You can easily create true one-at-a-time lazy-sequences. I've been working on
my own implementation of miniKanren (from The Reasoned Schemer) in Clojure.
It's been quite challenging since the original implementation assumes the
presence of TCO. Also one-at-time laziness is very much required here to
enforce interleaving of streams results and to avoid divergence. I was happy
to find I could get the same non-stack consuming behavior and that it turns
out to perform better than miniKanren under Racket.

[https://github.com/swannodette/logos/blob/master/src/logos/m...](https://github.com/swannodette/logos/blob/master/src/logos/minikanren.clj#L226)

------
msutherl
This link doesn't work for me. Were you trying to link to the following
thread?

[https://groups.google.com/forum/#!searchin/comp.lang.lisp/co...](https://groups.google.com/forum/#!searchin/comp.lang.lisp/comp.lang.lisp$20common$20lisp$20schem|sort:date/comp.lang.lisp/FkHeCSBxWZ0/R7oXXlQEVf4J)

~~~
gnosis
Nope. Just search google for:

    
    
      "secretly Scheme with bad syntax"
    

It should be the first hit.

It's a comp.lang.lisp post by Kent Pitman. Here's the header:

    
    
      Newsgroups: comp.lang.lisp
      From: Kent M Pitman <pit...@nhplace.com>
      Date: 15 Jul 2007 02:19:09 -0400
      Local: Sun, Jul 15 2007 1:19 am 
      Subject: Re: New Computer Language Shootout?
    

Here's a copy of the message:

<http://pastie.org/1461082>

------
zachbeane
[insert Arc joke here]

~~~
Entlin
Didn't you mean (insert Arc joke here) ?

~~~
troels
Doesn't matter. In Racket you can use either bracket-style, as you please.

~~~
kunjaan
I thought () was used for function applications and [] for those that weren't.
For example (let [x 3] ... )

~~~
epochwolf
Nope they are interchangeable.

~~~
kunjaan
The compiler may not mind, but isn't that what they are actually used for?

~~~
plorkyeran
Not quite; in (let ([x 1] [y 2]) (+ x y)) there's a set of parens which aren't
used for function (or macro) application.

