Uses for both static strong typed languages like Haskell and dynamic (strong) languages like Common LIsp - emacs

I was working with a Lisp dialect but also learning some Haskell as well. They share some similarities but the main difference in Common Lisp seems to be that you don't have to define a type for each function, argument, etc. whereas in Haskell you do. Also, Haskell is mostly a compiled language. Run the compiler to generate the executable.
My question is this, are there different applications or uses where a language like Haskell may make more sense than a more dynamic language like Common Lisp. For example, it seems that Lisp could be used for more bottom programming, like in building websites or GUIs, where Haskell could be used where compile time checks are more needed like in building TCP/IP servers or code parsers.
Popular Lisp applications:
Emacs
Popular Haskell applications:
PUGS
Darcs
Do you agree, and are there any studies on this?

Programming languages are tools for thinking with. You can express any program in any language, if you're willing to work hard enough. The chief value provided by one programming language over another is how much support it gives you for thinking about problems in different ways.
For example, Haskell is a language that emphasizes thinking about your problem in terms of types. If there's a convenient way to express your problem in terms of Haskell's data types, you'll probably find that it's a convenient language to write your program in.
Common Lisp's strengths (which are numerous) lie in its dynamic nature and its homoiconicity (that is, Lisp programs are very easy to represent and manipulate as Lisp data) -- Lisp is a "programmable programming language". If your program is most easily expressed in a new domain-specific language, for example, Lisp makes it very easy to do that. Lisp (and other dynamic languages) are a good fit if your problem description deals with data whose type is poorly specified or might change as development progresses.
Language choice is often as much an aesthetic decision as anything. If your project requirements don't limit you to specific languages for compatibility, dependency, or performance reasons, you might as well pick the one you feel the best about.

You're opening multiple cans of very wriggly worms. First off, the whole strongly vs weakly typed languages can. Second, the functional vs imperative language can.
(Actually, I'm curious: by "lisp dialect" do you mean Clojure by any chance? Because it's largely functional and closer in some ways to Haskell.)
Okay, so. First off, you can write pretty much any program in pretty much any normal language, with more or less effort. The purported advantage to strong typing is that a large class of errors can be detected at compile time. On the other hand, less typeful languages can be easier to code in. Common Lisp is interesting because it's a dynamic language with the option of declaring and using stronger types, which gives the CL compiler hints on how to optimize. (Oh, and real Common Lisp is usually implemented with a compiler, giving you the option of compiling or sticking with interpreted code.)
There are a number of studies about comparing untyped, weakly typed, and strongly typed languages. These studies invariably either say one of them is better, or say there's no observable difference. There is, however, little agreement among the studies.
The biggest area in which there may be some clear advantage is in dealing with complicated specifications for mathematical problems. In those cases (cryptographic algorithms are one example) a functional language like Haskell has advantages because it is easier to verify the correspondence between the Haskell code and the underlying algorithm.

I come mostly from a Common Lisp perspective, and as far as I can see, Common Lisp is suited for any application.
Yes, the default is dynamic typing (i.e. type detection at runtime), but you can declare types anyway for optimization (as a side note for other readers: CL is strongly typed; don't confuse weak/strong with static/dynamic!).
I could imagine that Haskell could be a bit better suited as a replacement for Ada in the avionics sector, since it forces at least all type checks at compile time.
I do not see how CL should not be as useful as Haskell for TCP/IP servers or code parsers -- rather the opposite, but my contacts with Haskell have been brief so far.

Haskell is a pure functional language. While it does allow imperative constructs (using monads), it generally forces the programmer to think the problem in a rather different way, using a more mathematical-oriented approach. You can't reassign another value to a variable, for example.
It is claimed that this reduces the probability of making some types of mistakes. Moreover, programs written in Haskell tend to be shorter and more concise than those written in typical programming languages. Haskell also makes heavy use of non-strict, lazy evaluation, which could theoretically allow the compiler to make optimizations not otherwise possible (along with the no-side-effects paradigm).
Since you asked about it, I believe Haskell's typing system is quite nice and useful. Not only it catches common errors, but it can also make code more concise (!) and can effectively replace object-oriented constructs from common OO languages.
Some Haskell development kits, like GHC, also feature interactive environments.

The best use for dynamic typing that I've found is when you depend on things that you have no control over so it could as well be used dynamically. For example getting information from XML document we could do something like this:
var volume = parseXML("mydoc.xml").speaker.volume()
Not using duck typing would lead to something like this:
var volume = parseXML("mydoc.xml").getAttrib["speaker"].getAttrib["volume"].ToString()
The benefit of Haskell on the other hand is in safety. You can for example make sure, using types, that degrees in Fahrenheit and Celsius are never mixed unintentionally. Besides that I find that statically typed languages have better IDEs.

Related

Discovering the "Core" Entities and Macros of Common Lisp

While reading Peter Seibel's "Practical Common Lisp", I learned that aside from the core parts of the language like list processing and evaluating, there are macros like loop, do, etc that were written using those core constructs.
My question is two-fold. First is what exactly is the "core" of Lisp? What is the bare minimum from which other things can be re-created, if needed? The second part is where can one look at the code of the macros which come as part of Common Lisp, but were actually written in Lisp? As a side question, when one writes a Lisp implementation, in what language does he do it?
what exactly is the "core" of Lisp? What is the bare minimum from which other things can be re-created, if needed?
The minimum set of syntactic operators were called "special forms" in CLtL. The term was renamed to "special operators" in ANSI CL. There are 24 of them. This is well explained in CLtL section "Special Forms". In ANSI CL they are 25.
where can one look at the code of the macros which come as part of Common Lisp, but were actually written in Lisp?
Many Common Lisp implementations are free software (list); you can look at their source code. For example, here for SBCL, here for GNU clisp, etc.
when one writes a Lisp implementation, in what language does he do it?
Usually a Lisp implementation consists of
a lower-level part, written in a system programming language. This part includes the implementation of the function call mechanism and of the runtime part of the 24 special forms. And
a higher-level part, for which Lisp itself is used because it would be too tedious to write everything in the system programming language. This usually includes the macros and the compiler.
The choice of the system programming language depends. For implementations that are built on top of the Java VM, for example, the natural choice is Java. For implementations that include their own memory management, it is often C, or some Lisp extensions with similar semantics than C (i.e. where you have fixed-width integer types, explicit pointers etc.).
First is what exactly is the "core" of Lisp? What is the bare minimum from which other things can be re-created, if needed?
Most Lisps have a core of primitive constructs, which is usually written in C (or maybe assembly). The usual reason for choosing those languages is performance. The bare minimum from which other things can be re-created depends on how bare-minimum you want to go. That is to say, you don't need much to be Turing-complete. You really only need lambdas for your language to have a bare minimum, from which other things can be created. Though, typically, people also include defmacro, cond, defun, etc. Those things aren't strictly necessary, but are probably what you mean by "bare minimum" and what people usually include as primitive language constructs.
The second part is where can one look at the code of the macros which come as part of Common Lisp, but were actually written in Lisp?
Typically, you look in in the Lisp sources of the language. Sometimes, though, your macro is not a genuine macro and is a primitive language construct. For such things, you may also need to look in the C sources to see how these really primitive things are implemented.
Of course, if your Lisp implementation is not open-source, you need to disassemble its binary files and look at them piece-by-piece in order to understand how primitives are implemented.
As a side question, when one writes a Lisp implementation, in what language does he do it?
As I said above, C is a common choice, and assembly used to be more common. Though, there are Lisps written in high-level languages like Ruby, Python, Haskell, and even Lisp itself. The trade-off here is performance vs. readability and comprehensibility.
If you want a more-or-less canonical example of a Lisp to look at which is totally open-source, check out Emacs' source code. Of course, this isn't Common Lisp, although there is a cl package in the Emacs core which implements a fairly large subset of Common Lisp.

What are the actual differences between Scheme and Common Lisp? (Or any other two dialects of Lisp)

Note: I am not asking which to learn, which is better, or anything like that.
I picked up the free version of SICP because I felt it would be nice to read (I've heard good stuff about it, and I'm interested in that sort of side of programming).
I know Scheme is a dialect of Lisp and I wondered: what is the actual difference is between Scheme and, say, Common Lisp?
There seems to be a lot about 'CL has a larger stdlib...Scheme is not good for real-world programming..' but no actual thing saying 'this is because CL is this/has this'.
This is a bit of a tricky question, since the differences are both technical and (more importantly, in my opinion) cultural. An answer can only ever provide an imprecise, subjective view. This is what I'm going to provide here. For some raw technical details, see the Scheme Wiki.
Scheme is a language built on the principle of providing an elegant, consistent, well thought-through base language substrate which both practical and academic application languages can be built upon.
Rarely will you find someone writing an application in pure R5RS (or R6RS) Scheme, and because of the minimalistic standard, most code is not portable across Scheme implementations. This means that you will have to choose your Scheme implementation carefully, should you want to write some kind of end-user application, because the choice will largely determine what libraries are available to you. On the other hand, the relative freedom in designing the actual application language means that Scheme implementations often provide features unheard of elsewhere; PLT Racket, for example, enables you to make use of static typing and provides a very language-aware IDE.
Interoperability beyond the base language is provided through the community-driven SRFI process, but availability of any given SRFI varies by implementation.
Most Scheme dialects and libraries focus on functional programming idioms like recursion instead of iteration. There are various object systems you can load as libraries when you want to do OOP, but integration with existing code heavily depends on the Scheme dialect and its surrounding culture (Chicken Scheme seems to be more object-oriented than Racket, for instance).
Interactive programming is another point that Scheme subcommunities differ in. MIT Scheme is known for strong interactivitiy support, while PLT Racket feels much more static. In any case, interactive programming does not seem to be a central concern to most Scheme subcommunities, and I have yet to see a programming environment similarly interactive as most Common Lisps'.
Common Lisp is a battle-worn language designed for practical programming. It is full of ugly warts and compatibility hacks -- quite the opposite of Scheme's elegant minimalism. But it is also much more featureful when taken for itself.
Common Lisp has bred a relatively large ecosystem of portable libraries. You can usually switch implementations at any time, even after application deployment, without too much trouble. Overall, Common Lisp is much more uniform than Scheme, and more radical language experiments, if done at all, are usually embedded as a portable library rather than defining a whole new language dialect. Because of this, language extensions tend to be more conservative, but also more combinable (and often optional).
Universally useful language extensions like foreign-function interfaces are not developed through formal means but rely on quasi-standard libraries available on all major Common Lisp implementations.
The language idioms are a wild mixture of functional, imperative, and object-oriented approaches, and in general, Common Lisp feels more like an imperative language than a functional one. It is also extremely dynamic, arguably more so than any of the popular dynamic scripting languages (class redefinition applies to existing instances, for example, and the condition handling system has interactivity built right in), and interactive, exploratory programming is an important part of "the Common Lisp way." This is also reflected in the programming environments available for Common Lisp, practically all of which offer some sort of direct interaction with the running Lisp compiler.
Common Lisp features a built-in object system (CLOS), a condition handling system significantly more powerful than mere exception handling, run-time patchability, and various kinds of built-in data structures and utilites (including the notorious LOOP macro, an iteration sublanguage much too ugly for Scheme but much too useful not to mention, as well as a printf-like formatting mechanism with GOTO support in format strings).
Both because of the image-based, interactive development, and because of the larger language, Lisp implementations are usually less portable across operating systems than Scheme implementations are. Getting a Common Lisp to run on an embedded device is not for the faint of heart, for example. Similarly to the Java Virtual Machine, you also tend to encounter problems on machines where virtual memory is restricted (like OpenVZ-based virtual servers). Scheme implementations, on the other hand, tend to be more compact and portable. The increasing quality of the ECL implementation has mitigated this point somewhat, though its essence is still true.
If you care for commercial support, there are a couple of companies that provide their own Common Lisp implementations including graphical GUI builders, specialized database systems, et cetera.
Summing up, Scheme is a more elegantly designed language. It is primarily a functional language with some dynamic features. Its implementations represent various incompatible dialects with distinctive features. Common Lisp is a fully-fledged, highly dynamic, multi-paradigm language with various ugly but pragmatic features, whose implementations are largely compatible with one another. Scheme dialects tend to be more static and less interactive than Common Lisp; Common Lisp implementations tend to be heavier and trickier to install.
Whichever language you choose, I wish you a lot of fun! :)
Some basic practical differences:
Common Lisp has separate scopes for variables and functions; whereas in Scheme there is just one scope -- functions are values and defining a function with a certain name is just defining a variable set to the lambda. As a result, in Scheme you can use a function name as a variable and store or pass it to other functions, and then perform a call with that variable as if it were a function. But in Common Lisp, you need to explicitly convert a function into a value using (function ...), and explicitly call a function stored in a value using (funcall ...)
In Common Lisp, nil (the empty list) is considered false (e.g. in if), and is the only false value. In Scheme, the empty list is considered true, and (the distinct) #f is the only false value
That's a hard question to answer impartially, especially because many of the LISP folks would classify Scheme as a LISP.
Josh Bloch (and this analogy may not be his invention) describes choosing a language as being akin to choosing a local pub. In that light, then:
The "Scheme" pub has a lot of programming-languages researchers in it. These people spend a lot of attention on the meaning of the language, on keeping it well-defined and simple, and on discussing innovative new features. Everyone's got their own version of the language, designed to allow them to explore their own particular corner of programming languages. The Scheme people really like the parenthesized syntax that they took from LISP; it's flexible and lightweight and uniform and removes many barriers to language extension.
The "LISP" pub? Well... I shouldn't comment; I haven't spent enough time there :).
scheme:
orginally very few specifications (new R7RS seems to be heavier)
due to the easy syntax, scheme can be learned quickly
implementations provide additional functions, but names can differ in different implementations
common lisp:
many functions are defined by the bigger specification
different namespace for functions and variables (lisp-2)
that are some points, sure there are many more, which i don't remember right now.

Is there any benefits to learning LISP?

I am a pretty experienced Ruby, Objective C, and Java programmer and I was watching a video on emacs (because I have been using Vi) and noticed that it is also a LISP interpreter. That spiked my interest, and brought up an interesting question: For someone that knows modern high level languages such as Ruby, Java ,and Objective C, is there any practical benefit to learning LISP? Would I gain anything by setting aside some time to learn LISP or not? I would like to hear what you guys have to say. Thanks.
There are definitely benefits to learning a language built on a different paradigm from the one you are used to (which I note are merely object oriented with strong imperative roots). LISP is the granddaddy of functional languages (one of my favourites, Scheme, is a LISP dialect).
Besides widening your horizons, functional languages and constructs are highly likely to grow further in importance as a reasonably straightforward way of using multi-core hardware efficiently.
LISP as such might not be my recommendation to start with, since it's enormously fragmented: on the other hand, there's a lot of history, and you can make use of it directly if you plan on moving to Emacs.
Lisp, in a sense, is the logical extension of von Neumann's revelation that "code is data is code".
The things figured out in Lisp before 82 or so are still working their way into mainstream programming languages like C# and Python. Due to the reasonably uniform Lisp syntax, they probably won't ever get all the way in with the ease of using them in Lisp.
Things like:
dynamic typing -- Possibly a Lisp invention, possibly smalltalk. Not sure.
object orientation -- mooched from Smalltalk by Lisp I think
reflection -- C# just got this one
DSLs in-language -- hello Linq.
macros -- a few ultra-researchy languages have these now besides Lisp
compilation in the interpreter -- never heard of other languages having this one
And other stuff I can't think up on the fly.
I suggest you get hold of a good Lisp book (they abound on the web) and try some Lisp yourself. You will be amazed to find that this 50 year old language is so "modern" and in some respect, way ahead of other "modern" languages. (For instance, find out why Lisp is called the programmable programming language). If you are too lazy to actually try some Lisp code yourself, read this and this.
Watch some of these: http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/
Learning Lisp per se isn't particularly practical, but it will make you a better programmer as you can apply the understanding you gain to languages you think you already know.

Macros: What's the benefit?

Paul Graham writes:
For example, types seem to be an
inexhaustible source of research
papers, despite the fact that static
typing seems to preclude true macros--
without which, in my opinion, no
language is worth using.
What's the big deal with macros? I haven't spent a whole lot of time with them, but from the legacy C/C++ I've worked with they appear to be mostly used as a hack before templates/generics existed.
It's hard to imagine that
DECLARELIST(StrList, string);
StrList slist;
is somehow preferable to
List<String> slist;
Am I missing something?
Then there's the usage as a pseudo-function, like MAKEPOINTS:
POINTS MAKEPOINTS(
DWORD dwValue
);
Why not define it as a function instead? Is this some optimization, where you avoid code duplication without having the added overhead of another stack frame?
Then there's also tricky control flow things involving GOTO, which seem to be of dubious value.
What's so great about macros? They're less type safe (in C and C++) (right?). Why won't Paul Graham program without them?
LISP macros are an entirely different beast. C/C++ macros can merely replace a piece of text with abother piece of text using an extremely basic language. Whereas a LISP program is (after "reading") is a LISP data structure and can therefore be manipulated using the whole language.
With such macros, you could (given you're a really clever hacker) vastly extend the language and everybody could use it relatively easily, since you did it with macros. Take for example the the Common Lisp Object System. At its core, the language has nothing even remotely like objects. It is entirely implemented in the language itself, including a relatively simple syntax for use - using macros.
Of course macros are less necessary when the language has most things you'd every want built-in. OTOH, the LISP fans are of the opinion that a sufficiently simple language (LISP) with sufficiently powerful metaprogramming capabilities (macros) is better since new concepts can be incorporated into the language without changing the spec or working implementations. But the most compelling example for macro usage is the DSL area. Ruby on Rails and others show every day how useful DSLs can be. Yes, Ruby doesn't have macros, it just exploits how much Ruby syntax can be bent. In other languages, or when even Ruby's syntax isn't flexible enough, you need macros or a fully-blown parser/interpreter to implement a complex DSL.
Macros are really only good for two things in C/C++, and should generally be the tool of last resort (if you can accomplish something without using macros, do so).
Creating new syntactic structures or abstractions that do not exist in the language.
Eliminating duplication, especially between things that must be in sync with each other.
It's almost never to use a macro as a function.
You also have to realize that LISP macros are not C/C++ macros.

What features is lisp lacking? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I have read that most languages are becoming more and more like lisp, adopting features that lisp has had for a long time. I was wondering, what are the features, old or new, that lisp does not have? By lisp I mean the most common dialects like Common Lisp and Scheme.
This question has been asked a million times, but here goes. Common Lisp was created at a time when humans were considered cheap, and machines were considered expensive. Common Lisp made things easier for humans at the expense of making it harder for computers. Lisp machines were expensive; PCs with DOS were cheap. This was not good for its popularity; better to get a few more humans making mistakes with less expressive languages than it was to buy a better computer.
Fast forward 30 years, and it turns out that this isn't true. Humans are very, very expensive (and in very short supply; try hiring a programmer), and computers are very, very cheap. Cheaper than dirt, even. What today's world needs is exactly what Common Lisp offered; if Lisp were invented now, it would become very popular. Since it's 30-year-old (plus!) technology, though, nobody thought to look at it, and instead created their own languages with similar concepts. Those are the ones you're using today. (Java + garbage collection is one of the big innovations. For years, GC was looked down upon for being "too slow", but of course, a little research and now it's faster than managing your own memory. And easier for humans, too. How times change...)
Pass-by-reference (C++/C#)
String interpolation (Perl/Ruby) (though a feature of CL21)
Nice infix syntax (though it's not clear that it's worth it) (Python)
Monadic 'iteration' construct which can be overloaded for other uses (Haskell/C#/F#/Scala)
Static typing (though it's not clear that it's worth it) (many languages)
Type inference (not in the standard at least) (Caml and many others) (though CL does some type inference, unlike Python)
Abstract Data Types (Haskell/F#/Caml)
Pattern matching (Haskell/F#/Caml/Scala/others) (in CL, there are libs like optima)
Backtracking (though it's not clear that it's worth it) (Prolog)
ad-hoc polymorphism (see Andrew Myers' answer)
immutable data structures (many languages) (available through libraries, like Fsets
lazy evaluation (Haskell) (available through libraries, like clazy or a cl21 module)
(Please add to this list, I have marked it community wiki.)
This just refers to the Common Lisp and Scheme standards, because particular implementations have added a lot of these features independently. In fact, the question is kind of mistaken. It's so easy to add features to Lisp that it's better to have a core language without many features. That way, people can customize their language to perfectly fit their needs.
Of course, some implementations package the core Lisp with a bunch of these features as libraries. At least for Scheme, PLT Scheme provides all of the above features*, mostly as libraries. I don't know of an equivalent for Common Lisp, but there may be one.
*Maybe not infix syntax? I'm not sure, I never looked for it.
For Common Lisp, I think the following features would be worth adding to a future standard, in the ridiculously unlikely hypothetical situation that another standard is produced. All of these are things that are provided by pretty much every actively maintained CL implementation in subtly incompatible ways, or exist in widely used and portable libraries, so having a standard would provide significant benefits to users while not making life unduly difficult for implementors.
Some features for working with an underlying OS, like invoking other programs or handling command line arguments. Every implementation of CL I've used has something like this, and all of them are pretty similar.
Underlying macros or special forms for BACKQUOTE, UNQUOTE and UNQUOTE-SPLICING.
The meta-object protocol for CLOS.
A protocol for user-defined LOOP clauses. There are some other ways LOOP could be enhanced that probably wouldn't be too painful, either, like clauses to bind multiple values, or iterate over a generic sequence (instead of requiring different clauses for LISTs and VECTORs).
A system-definition facility that integrates with PROVIDE and REQUIRE, while undeprecating PROVIDE and REQUIRE.
Better and more extensible stream facilities, allowing users to define their own stream classes. This might be a bit more painful because there are two competing proposals out there, Gray streams and "simple streams", both of which are implemented by some CL implementations.
Better support for "environments", as described in CLTL2.
A declaration for merging tail calls and a description of the situations where calls that look like tail calls aren't (because of UNWIND-PROTECT forms, DYNAMIC-EXTENT declarations, special variable bindings, et c.).
Undeprecate REMOVE-IF-NOT and friends. Eliminate the :TEST-NOT keyword argument and SET.
Weak references and weak hash tables.
User-provided hash-table tests.
PARSE-FLOAT. Currently if you want to turn a string into a floating point number, you either have to use READ (which may do all sorts of things you don't want) or roll your own parsing function. This is silly.
Here are some more ambitious features that I still think would be worthwhile.
A protocol for defining sequence classes that will work with the standard generic sequence functions (like MAP, REMOVE and friends). Adding immutable strings and conses alongside their mutable kin might be nice, too.
Provide a richer set of associative array/"map" data types. Right now we have ad-hoc stuff built out of conses (alists and plists) and hash-tables, but no balanced binary trees. Provide generic sequence functions to work with these.
Fix DEFCONSTANT so it does something less useless.
Better control of the reader. It's a very powerful tool, but it has to be used very carefully to avoid doing things like interning new symbols. Also, it would be nice if there were better ways to manage readtables and custom reader syntaxes.
A read syntax for "raw strings", similar to what Python offers.
Some more options for CLOS classes and slots, allowing for more optimizations and better performance. Some examples are "primary" classes (where you can only have one "primary class" in a class's list of superclasses), "sealed" generic functions (so you can't add more methods to them, allowing the compiler to make a lot more assumptions about them) and slots that are guaranteed to be bound.
Thread support. Most implementations either support SMP now or will support it in the near future.
Nail down more of the pathname behavior. There are a lot of gratuitously annoying incompatibilities between implementations, like CLISP's insistance on signaling an error when you use PROBE-FILE on a directory, or indeed the fact that there's no standard function that tells you whether a pathname is the name of a directory or not.
Support for network sockets.
A common foreign function interface. It would be unavoidably lowest-common-denominator, but I think having something you could portably rely upon would be a real advantage even if using some of the cooler things some implementations provide would still be relegated to the realm of extensions.
This is in response to the discussion in comments under Nathan Sanders reply. This is a bit much for a comment so I'm adding it here. I hope this isn't violating Stackoverflow etiquette.
ad-hoc polymorphism is defined as different implementations based on specified types. In Common Lisp using generic methods you can define something like the following which gives you exactly that.
;This is unnecessary and created implicitly if not defined.
;It can be explicitly provided to define an interface.
(defgeneric what-am-i? (thing))
;Provide implementation that works for any type.
(defmethod what-am-i? (thing)
(format t "My value is ~a~%" thing))
;Specialize on thing being an integer.
(defmethod what-am-i? ((thing integer))
(format t "I am an integer!~%")
(call-next-method))
;Specialize on thing being a string.
(defmethod what-am-i? ((thing string))
(format t "I am a string!~%")
(call-next-method))
CL-USER> (what-am-i? 25)
I am an integer!
My value is 25
NIL
CL-USER> (what-am-i? "Andrew")
I am a string!
My value is Andrew
NIL
It can be harder than in more popular languages to find good libraries.
It is not purely functional like haskell
Whole-program transformations. (It would be just like macros, but for everything. You could use it to implement declarative language features.) Equivalently, the ability to write add-ons to the compiler. (At least, Scheme is missing this. CL may not be.)
Built-in theorem assistant / proof checker for proving assertions about your program.
Of course, I don't know of any other language that has these, so I don't think there's much competition in terms of features.
You are asking the ronge question. The language with the most features isnt the best. A language needs a goal.
We could add all of this and more
* Pass-by-reference (C++/C#)
* String interpolation (Perl/Ruby)
* Nice infix syntax (though it's not clear that it's worth it) (Python)
* Monadic 'iteration' construct which can be overloaded for other uses (Haskell/C#/F#/Scala)
* Static typing (though it's not clear that it's worth it) (many languages)
* Type inference (not in the standard at least) (Caml and many others)
* Abstract Data Types (Haskell/F#/Caml)
* Pattern matching (Haskell/F#/Caml/Scala/others)
* Backtracking (though it's not clear that it's worth it) (Prolog)
* ad-hoc polymorphism (see Andrew Myers' answer)
* immutable data structures (many languages)
* lazy evaluation (Haskell)
but that would make a good language. A language is not functional if you use call by ref.
If you look at the new list Clojure. Some of them are implemented but other that CL has are not and that makes for a good language.
Clojure for example added some:
ad-hoc polymorphism
lazy evaluation
immutable data structures
Type inference (most dynamic languages have compilers that do that)
My Answer is:
Scheme schooled stay as it is.
CL could add some ideos to the standard if they would make a new one.
Its LISP most can be added with libs.
Decent syntax. (Someone had to say it.) It may be simple/uniform/homoiconic/macro-able/etc, but as a human, I just loathe looking at it :)
It's missing a great IDE