Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Scheme or Common Lisp?

Name: Anonymous 2010-07-22 9:02

Yes, it's a “which programming language to leran ???” thread, but this time it's ...more specific I guess?

So I already know C and Perl and wish to acquaint myself with other paradigms than the procedural and object-oriented ones I've become uncomfortably familiar with (i.e., functional). I also intend to learn Haskell at some point in the future in order to complete the holy trinity of syntaxes.

So, /anus/. Regarding the thread title, what are the differences that you find make you prefer one Lisp dialect to another? Is there even much of a difference? Or did you just choose one as your way of saying, “I've read SICP”?

Name: Anonymous 2010-07-22 9:11

It doesn't really matter. I prefer guaranteed TCO, hygenic macros, and single namespace of Scheme. Others don't. I also fucking hate emacs.

Name: Anonymous 2010-07-22 9:34

>>1
U MENA HASKAL?

Name: Anonymous 2010-07-22 11:30

>>2
guaranteed TCO
The Forced Optimization of Tail Calls

Name: Anonymous 2010-07-22 11:54

>>4
Yeah, what's up with this stupid premature optimization?  That's the reason I don't use Scheme.

Name: Anonymous 2010-07-22 16:20

None. Learn a real life one.

Name: Anonymous 2010-07-22 17:19

>>6
He knows C.

Name: Anonymous 2010-07-22 17:22

>>7
and Perl

Name: Anonymous 2010-07-22 18:28

>>2
What editor do you use then?

I hate Emacs aswell - I'm a vim user - but I want to learn Scheme.

vim + Lisp fucking sucks.

Name: Anonymous 2010-07-22 18:33

>>9
DrRacket.

Name: Anonymous 2010-07-22 18:36

>>10
``DrRacket''...?

As if anyone would name their software with something that silly.

Seriously, what editor do you use?

Name: Anonymous 2010-07-22 18:45

>>1
I prefer Scheme, but if you learn one switching to the other shouldn't be too difficult.
>>9
There's no obligation to use emacs with Scheme or Lisp, it's just what a lot of us use. You could try ARSE, it's a work-in-progress vi-a-like that comes with s9fes and Neils Holm is looking for feedback, but you can use gedit, or whatever. I even think there is a scheme plugin for Eclipse
>>11
racket-lang.org

Name: Anonymous 2010-07-22 18:45

I prefer Common Lisp, for a variety of reasons (mostly practical ones). Scheme can technically do the same things as Common Lisp, but you'll have to reinvent a lot of wheels in R5RS to get the same functionality (wheels which have been reinvented by serious Scheme implementations, but unlike CL's these features are not all portable across many other implementations. Implementing some CL features in Scheme may require you to hack the underlying implementation or make your own implementation as they're just too extensive). R6RS Scheme does move more closely to what CL offers, and the base library and macro support is more extensive.

What Scheme has that Common Lisp doesn't? Full continuation support(call/cc) and proper hygienic macro support and guranteed TCO.

In practice, all real CL implementations do support TCO, however you tend to have the freedom of turning it on and off, depending on your needs, and there are some CL features which don't play that nicely with TCO (optional dynamic scope, which implies one needs to use a variable value stack and have support for unwinding that stack automatically), TCO is just considered an optimization, which is why it wasn't included in the standard as mandatory (TCO is actually much more, if you think about it yourself, or cheat by reading the lambda papers, for example, TCO can be used as the ultimate goto, without most of the issues associated with goto...).

As for call/cc, it doesn't play too well with unwind-protect and it again forces too many choices on implementors (like forced TCO). It's supported by 3rd party libraries which are also mostly portable, but it usually requires a code walker, as it's done by performing CPS transforms (some implementations also support the low-level version of dumping heap/stack and restoring it).

As for hygienic macro systems, I'm not a huge fan of them myself, they force hygiene on your macros, while restricting some of your power. Common Lisp provides enough tools to let you achieve hygiene(gensym, make-symbol, packages,...), however the responsibility lies on the programmer to know what he's doing (just like any other kind of programming...). Scheme's complex hygienic macro systems do make writing some types of macros easier, while others a huge pain, CL's low-level macro system is probably one of the simplest in existence, and it works as a compiler hook which just calls your macro expander, which destructures the arguments(if you wish), and then you can use any real Lisp code to generate the expanded form. Note: you can implement hygienic macros in Common Lisp, protably, however almost no CLer is interested in doing it as they're fairly content with defmacro(there are a handful of toy implementations which show how to do it, if you're curious).

Now the main difference between Scheme and Common Lisp(besides Scheme trying to be minimal yet beautiful and Common Lisp attempting to be complete and power), is that Scheme has a one-namespace philosophy, while Common Lisp, has a 2-n+ namespace philosophy. The main consequence is that in CL, a symbol has a normal value and a functional value/slot, while in Scheme, a symbol has only a value, and defining a function, results in binding the symbol to that value in the lexical scope of that form, while in CL, you can use the same symbol to name both a variable and a function, without causing conflicts. This allows more robust low-level macro writing, as well as having arguments/variables of the same name as the function (for example, you can have a function that has an argument named 'list', that works fine in CL, but in Scheme, you'll see people name it 'lst','lyst' or whatever, to avoid shadowing the list function). The CL 2 namespace way is called Lisp-2, and the Scheme one is called Lisp-1. I favor Lisp-2 strongly, but I can see why others like Lisp-1. The disadvantage of Lisp-2 is that it makes writing some types of functional code a bit more verbose(the #' reader macro, or (function ...) special-operator being required when referring to a function by symbol name, when the symbol isn't in the CAR position, as well as having to use funcall to call variables having functional values). Read http://www.nhplace.com/kent/Papers/Technical-Issues.html for more details.

Common Lisp also allows optional declarations, which allow you to give hints to the compiler allowing better optimizations. Some CL compilers generate pretty fast code (like SBCL, who can also infer types to some degree), and are well-known for their speed.

Personally, I learned Scheme by reading my SICP first, and then moved to Common Lisp for most of my real-world programming needs. If you choose to learn CL, I'd recommend looking at Practical Common Lisp, maybe look at PG's ANSI CL, PAIP, AMOP, and of course have the Hyperspec and ClTl2 as referneces.
There's also quite a few notable Scheme books, my favorites besides SICP would be Lisp in Small Pieces(compiler/interpreter building) and the Lambda papers.

Or did you just choose one as your way of saying, “I've read SICP”?
I found that CL gives me a huge amount of freedom when writing code, like none other that I've encountered before. This was the main reason that I even learned Lisp - I was being pissed that the language that I was coding in was restricting me in very silly ways and I had to write a lot of boilerplate (it was Java/C#, but at that time I knew C, ML, some x86 asm and some others). Currently, I'm using CL for the majority of my high-level programming needs and C (sometimes with some asm) for mostly low-level needs.

Name: >>13 2010-07-22 18:58

Forgot to mention that Scheme's hygienic macro system syntax-case (in R6RS), is just as powerful as CL's low-level macros (when I wrote that post, I mostly had syntax-rules in mind, which is not as powerful).

I probably had some other points in there that may stir a flamewars, but I'll leave it at that.

Name: Scheme weenie 2010-07-22 19:05

Two points, then I'll shut up
As for hygienic macro systems, I'm not a huge fan of them myself, they force hygiene on your macros, while restricting some of your power.
Syntax-rules aside, what power are you missing with syntax-case or syntactic closures or ER macros? Especially given that an implementation of defmacro is like 20 or so lines of code.

but in Scheme, you'll see people name it 'lst','lyst' or whatever, to avoid shadowing the list function).
Aside from the question of whether or not 'list' is an appropriate name for a function: 1) I'd just shadow it 2) I'm not sure how you can get better readability if the same name has two meanings 3) The macro point is, of course, mitigated by hygiene.

Name: Anonymous 2010-07-22 19:06

>>9
try :set lisp
Helped me when I was editing scheme.

>>12
FU, anyone editing in a lisp-like syntax should use an editor that supports auto-indenting lisp properly. It's a pain in the ass to indent by hand and even worse to read when not indented properly.

Name: >>15 2010-07-22 19:07

>>14
should have refreshed, you already answered my first point

Name: Anonymous 2010-07-22 19:11

In my experience the lisp-1/2 argument is very weird. Usually people say something like, "If I want my function argument to be a list, I want to call it 'list.' But then I can't use list!" Which sounds mildly convincing, except I've never actually had a function which took a list as an argument, and needed to create a new list internally, which wasn't better expressed by something like map.

Does a lisp-2er have some kind of function they can give as an example where lisp-1 namespaces result in awkward code? It may just be that I'm so used to scheme I have a kind of blind spot here.

Name: >>13 2010-07-22 19:28

>>15,18
I've written plenty of functions with arguments named like: string, array, list, cons, function and so on (in a Lisp-1, I'd name array as a arr, ar; list as lst, lyst; cons as pair or cns; function as fun or fn).

In a Lisp-2, it's very clean which one refers to which. If it's the car of the form, it calls the function/macro/special-operator, otherwise it's the variable. I know it's not a function as a function named by a symbol would be: #'string #'list #'cons or (function string) (function list) (function cons). #'
is merely a reader macro which reads as (function ...), while function is a special operator which looks up the function named by that symbol in the current lexical environment (it needs to be a special operator due to that and how it interacts with compilation).

Overall, it's just useful for 2 things: doesn't restict you when it comes to what names you give to variables, it's useful when it comes to low-level macros.

Name: Anonymous 2010-07-22 19:29

s/clean/clear/

Name: Anonymous 2010-07-22 19:29

>>14
Actually syntax-case is more powerful.

Name: Anonymous 2010-07-22 19:34

>>21
In what way? It's already proved that hygienic macros are doable in CL portably. The cool things about hygienic macros is the whole way they capture the lexical environment the macro is written in, but that can also be achieved in CL through a variety of techniques, however I can't remember a single case where I needed to do that intentionally, and I've written a lot of macros.

Name: >>15 2010-07-22 19:36

Overall, it's just useful for 2 things: doesn't restict you when it comes to what names you give to variables, it's useful when it comes to low-level macros.
So, as the latter isn't a problem in Scheme. It comes down to name restrictions. I can live with that, and like I said, I'm not afraid to shadow ;)

Name: Anonymous 2010-07-22 19:38

>>19
Overall, it's just useful [because it] doesn't restict you when it comes to what names you give to variables...
But this is exactly my question. What is a good example of a function where shadowing a built-in is awkward? Since I posted >>18 I even went back over some random code and couldn't find a single instance where it seems like I sidestepped the issue by using weird names.

I really don't use macros much, so I will probably not understand any macro arguments. I've only ever required syntax-rules for my needs.

Name: Anonymous 2010-07-22 19:49

>>22
Replacing every binding form or code walking is not doing something in portable CL. It is creating a new language. You wouldn't say every CL feature is doable in x86 assembly because SBCL exists.

Name: Anonymous 2010-07-22 19:57

>>25
You don't really need a full code-walker. See: http://p-cos.net/documents/hygiene.pdf
Also, it's possible to capture the lexical environment selectively without needing any new features. Assuming I'm writing some macro which would really need that feature, it can be done. It's a bit tricky to do it, but perfectly possible. There's some proof-of-concept macros showing how to do this in c.l.l, but it'd probably take me a while (and waste me half a day reading old posts on newsgroups) to find that thread again.

Name: Anonymous 2010-07-22 20:02

This thread has been closed and replaced with the following thread:

Subject: FEXPRS SUCK
Name:
Email:

Who cares about petty differences between CL and Scheme, lets hate something worth hating

Name: Anonymous 2010-07-22 20:05

>>27
Who is hating anything? Seems unanimous that the choice is pretty arbitrary.

Name: Anonymous 2010-07-22 20:07

>>27
They do suck for sure, but no sane Lisp has them.
The only "modern" Lisp that makes the mistake of having them instead of a compile-time macro system is newLISP(the excuse for having them is that  newLISP is interpreted-only).

It's also trivial to implement FEXPR's in Lisps which have macros, but don't have FEXPR's (the reverse is not true).

The only language with lisp in it's name worse than newLISP is probably BEELISP.

Name: Anonymous 2010-07-22 20:12

BEELISP.
I remember that thread on c.l.l. hilarious

Name: Anonymous 2010-07-22 20:25

>>26
Please read the papers you post, and the posts you reply to.

To achieve this, all binding forms (defvar, defun, defmacro, let, let*, flet, macrolet, and so on) have to be reimplemented

Name: Anonymous 2010-07-22 20:37

>>31
You can shadow a form. It does not mean it requires a full code walker. Besides, assuming you choose to use the full code walker approach, why would that be a huge issue? People have used code walkers in CL for a long time (some implementations even have support for them natively): they're used in CLOS and MOP, macroexpand-all, continuations via CPS and some other libraries. Some people don't even realize when code walkers are used. I'd also argue that it's not really a whole new language, as if it was a truly new language, you'd have different forms/special operators/macros... It's just extending the language. I'm not going to argue about this that much, as this depends on one's viewpoint, some people consider any of these as making a new language(examples):
1) creating new functions
2) creating new macros
3) shadowing symbols (packages)
4) defining symbol macros
and so on. It's perfectly possible to implement new languages using only portable means, but where does one draw the line?

I don't really care. Maybe one could draw the line at what can be done portably, or maybe one could draw the line when one has to implement their own compiler or interpreter. But then, what is the definition of a compiler? A macro itself is a piece of a compiler. Should the definition be limited to a full-fledged compiler only? However, a full-fledged compiler can still be done using only portable functions and macros...

tl;dr: I don't know where to draw this line, nor do I care about drawing it.

Name: Anonymous 2010-07-22 20:37

*shadow a symbol

Name: Anonymous 2010-07-22 21:48

>>32
You cannot shadow external symbols of the COMMON-LISP package.

Now that you bring it up, there are indeed several problems with code walkers:
1. They need to be able to transform everything to be fully effective, which is difficult with builtins, requires that full source code is available for everything and that everything is written in CL. For example, how many CPS transforms fall flat on their face when encountering MAPCAR?
2. They don't work well together. When two code walkers conflict, you cannot use one in one part of your code and the other in another part like you can with conflicting functions or macros.

In general requiring a global change to solve a local problem sucks. See also ``On the Expressive Power of Programming Languages'' by Matthias Felleisen.

Name: Anonymous 2010-07-22 22:00

>>34
No, what is prohibited in the standard (but actually allowed by most implementations, some even make it easier) is changing the value or rebinding it (of symbols in CL).

However, nothing prevents you from making another package and doing a shadowing import or merely, not importing some symbols from the CL package (symbols for you you can provide definitions, and the definitions you make can call the original ones).

The major reasoning for disallowing such things are:
1) You're changing the behaviour of code you didn't write and the functionality of other code may become unreliable/non-standard compliant
2) Even if you change the definition of a function, that function can be already inlined, or changing one macro definition won't change the expansions of already compiled code.

Of course, using packages to pick what symbols you like (and thus features) is perfectly permitted and that's what most people do when they want to change the behaviour of some symbols in the CL package portably.

Name: >>35 2010-07-22 22:02

>>34
In general requiring a global change to solve a local problem sucks.
True, however it might not require a true global change, for example, you could perform CPS within the body of some macro, instead of defining your own COMPILE and EVAL.

Name: Anonymous 2010-07-22 22:07

Any sufficiently complicated Common Lisp program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of R6RS.

Name: Anonymous 2010-07-22 22:17

Name: Anonymous 2010-07-22 22:33

>>38
Completly aware of that, however that does not prohibit the protable and recommended way of changing the behaviour of some symbol (actually, it's another symbol!). Here' I'll show how to define a CL where car and cdr have reversed their positions (it won't affect existing code, but any code using your car and cdr would be affected):


(cl:defpackage #:weird-lisp
  (:use #:cl)
  (:shadow #:car #:cdr))

(in-package #:weird-lisp)

(defun car (list)
  (cl:cdr list))

(defun cdr (list)
  (cl:car list))

(let ((a (cons 1 2)))
  (list (car a) (cdr a))) ;=> (2 1)

Completly portable and correct. Nothing in that issue prohibits this and this is the recommended way of "redefining" the language.

Name: Anonymous 2010-07-22 23:38

I am not the OP and this thread has been very informative. I've been meaning to ask this for some time. Thanks all. This thread has also raised my hopes for /prog/; for some reason it seems like a lot less of a shithole today than it normally does.

To get a bit more specific, which one should I use for game development? I've been a game developer for some time and I can no longer stand Sepples. I've been reading a lot of stuff from people like Paul Graham, and they all say you should learn a Lisp, so here I am. I've heard that generally CL will give you more optimization options, what with being able to declare types and such. On the other hand, Scheme has the Stalin compiler. I've heard it is also better oriented for functional programming, and functional code is likely to parallelize better. Getting used to functional programming at the same time as learning Lisp might be a good idea, and if the language isn't forcing me to do it I'll probably write everything procedural like I do now.

Also, what are your thoughts on Paul Graham's Lisp, Arc? It's a Lisp-1 with hygienic macros, but it has more special syntax than Scheme and is less functional. Has anyone here tried it?

Right now I'm leaning towards Scheme. Honestly the biggest reason I'm
turned off by CL is because of how much syntax it has; it seems like it has a lot more of a learning curve. I was going to run through SICP, then try to see if I can write a minimal game in Scheme and compile it with Stalin (something trivial like Tetris in OpenGL). Is this a good idea?

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List