

Lisp Tips - sabya
http://lisptips.com/

======
vinceguidry
I went through HtDP awhile back. Mind-blowing, changed the way I approached
programming, yada yada. Scheme held a special place in my heart for years
after.

Back then I would have loved to have found a job where I could have used it. I
settled for Ruby. After a year of using Ruby seriously, I started to wonder
again about using Scheme, so I took a look at some of the available options.

Naturally, like everyone else in this situation, I ran into the brick wall of
just not having the community support Ruby has, so it's very difficult to
justify using it on any project except purely personal projects, and even
then, it's more about exploring a domain rather than exploring a programming
paradigm, so I never did get to do anything serious in Lisp. Clojure's nice
and all, but the JVM is turning into quite the bit of baggage, hard to justify
using it over Ruby.

That's when I took another look at Ruby and realized it did pretty much
everything I needed, meta-programming-wise, why bother with continuations and
macros when you can use composition and module mixins to achieve practically
the same thing? (environment tracking and easy DSL creation) Sure it's not as
mathematically pretty as Lisp is, but Ruby syntax is still much prettier than
Lisp's.

After awhile I realized that the HtDP way of solving problems and the OO/SOLID
way work equally well. You'd just use one with a language like Ruby and the
other with a more functional paradigm like Lisp. OO is plenty flexible if you
avoid listening to the zealots.

One focuses on the functions/data and the other focuses on the
classes/objects. Screw that, I say focus on the domain. Make that logic as
tight as you can, then introduce interfaces to it. With that model, Ruby works
Just Fine.

~~~
klibertp
> Ruby syntax is still much prettier than Lisp's

No. Lisps have no syntax at all. You write your programs in AST form. It's not
possible to compare this to writing Ruby or Python. For the comparison to be
fair you'd have to write Python like this:

    
    
        Module(body=[
            Expr(value=Call(func=Name(id='map', ctx=Load()),
                            args=[Lambda(args=arguments(args=[Name(id='x', ctx=Param())],
                                                        vararg=None,
                                                        kwarg=None,
                                                        defaults=[]),
                                         body=BinOp(left=Name(id='x', ctx=Load()),
                                                    op=Pow(),
                                                    right=Num(n=2))),
                                  Call(func=Name(id='range', ctx=Load()),
                                       args=[Num(n=100)],
                                       keywords=[],
                                       starargs=None,
                                       kwargs=None)],
                            keywords=[],
                            starargs=None,
                            kwargs=None))
        ])
    
    

And I believe that in this case something like this:

    
    
        (map (lambda (x) (sqr x)) (in-range 100))
    

Wins hands down in beauty, readability and any other "metric" :)

~~~
vinceguidry
I don't get at all how you say that to get a decent comparison, you have to
write your Python/Ruby in AST form. That's just silly. Any language requires
multiple transformations before it can be run by the processor, Lisp is no
different.

S-expressions are definitely a syntax, that's close to the AST it parses into,
but not quite. You still need a parser, because there's still quite a bit of
ambiguity that gets introduced by language features like macros.

What's the point of printing out Python's AST and saying it isn't readable?
It's not _designed_ to be read by humans!

That last bit would look like this in idiomatic Ruby:

    
    
        (1..100).map {|x| x ** 2}
    

... which I think is far more readable than your Lisp, almost half the
characters, and it translates its intentions better, by putting the more
important information first, the values of the range being mapped, and
compactly representing the predicate function. You can omit the lambda keyword
entirely because syntax allows you to denote one in a much more legible way.
Can't do that with Scheme, there's no way to denote an inline function without
it. Guess what, that's syntax.

S-expressions sacrifice readability because not every programming idea needs
to be expressed exactly the same way. applying a lambda function should not be
expressed in the same way as passing a value as an argument. They're two
completely different actions, they solve two different problems, and that
should be reflected in the syntax. Otherwise you have to read the code more
closely to try to figure out what it's doing.

And what you're gaining, homoiconicity, is a neat trick, but I've learned that
it isn't really necessary for anything. I do find myself wanting it whenever
I'm doing something really abstract like AI programming, but it's not like I
really need it or anything. You can easily use language-specific meta-
programming to solve the same problems, and the learning curve for that is a
bit steep, but it will make you a better coder in the end.

~~~
lispm
> S-expressions are definitely a syntax

For data. s-expressions are not a syntax for Lisp. Only for data.

> You still need a parser, because there's still quite a bit of ambiguity that
> gets introduced by language features like macros.

Macros introduce no ambiguity. They are destructuring and/or transforming the
code.

Much less noise than your Ruby example:

    
    
        (mapcar 'sqr (in-range 100))
    
        (loop for n from 1 to 100 collect (sqr n))
    

Lisp as a programming language is based on words, tree structure and
indentation, not so much on special characters. That's different from Ruby.
But reading and parsing words is not really different to learn, otherwise you
would have problems reading this text, which has lots of words and few special
character.

~~~
vinceguidry
> For data. s-expressions are not a syntax for Lisp. Only for data.

Such a strange statement! Code IS data in Lisp.

> Macros introduce no ambiguity. They are destructuring and/or transforming
> the code.

And just what do you think syntax rules do? Any language could be represented
with s-expressions. They just choose not to because s-expressions are a pain
in the ass to read. The earlier example mapping square over a range expressed
the exact same idea, so the representation is identical. You could write code
to transform Ruby into s-expressions the same way Coffeescript compiles to
Javascript. Nobody has yet, guess why?

> Much less noise than your Ruby example:

One could argue that the glut of parentheses are themselves noise. There are
other ways of structuring Lisp programs that don't use them, but rather a one
statement per line syntax like every other language. Also that prefix notation
isn't natural for humans to read, dot notation is much more intuitive, which
is why it's used in so many languages. Also that the special characters in,
say, Ruby's block syntax reduce noise by providing visual cues to what parts
of your code are what.

But whatever, if you think

    
    
        (1..100).map {|x| x ** 2 }
    

is noisy, then there's really no point in arguing with you, because we see the
world two totally different ways.

And this:

    
    
        (loop for n from 1 to 100 collect (sqr n))
    

...looks exactly like a Ruby-style DSL implemented in Lisp. If I saw that in
someone's code I'd be like, WTF is that doing? A method with 8 parameters? Oh
wait, it's a macro. Why use a macro for that, what's wrong with building the
range with a function instead of reimplementing BASIC in Lisp? Isn't the whole
point to get away from imperative style?

~~~
lispm
> Such a strange statement! Code IS data in Lisp.

Code is represented as data. But that does not mean any data is code.

For example

    
    
        (defun foo (a) (let ((b 10)) (+ a b)))
    

is valid data and valid code.

    
    
        (defun (foo a) (let b 10 then (+ a b)))
    

Above is valid data, but not valid code.

    
    
        CL-USER 27 > (defun (foo a) (let b 10 then (+ a b)))
    
        Error: (FOO A) is neither of type SYMBOL nor a list of the form (SETF SYMBOL).
    
    

The syntax for DEFUN is:

    
    
        defun function-name lambda-list [[declaration* | documentation]] form*
    

The syntax for LET is:

    
    
        let ({var | (var [init-form])}*) declaration* form*
    

Both syntax definitions are violated.

Obviously, the syntax of s-expressions is not enough to describe the syntax of
Lisp. Far from it. S-Expressions just describe a textual syntax for data:
symbols, numbers, strings, lists, cons cells, ... But it does not describe the
syntax for defining functions, defining variables, exception handlers,
function calls, etc.

> They just choose not to because s-expressions are a pain in the ass to read.

They aren't.

> Isn't the whole point to get away from imperative style?

Lisp makes no commitment to a particular style. 'imperative' is just fine. As
is functional, object-oriented, rule-based, ...

------
cleverjake
too bad it hasn't been updated in a half a year :/

I would really like to find an active version of something like this

~~~
zachbeane
I ran out of tips!

I've been collecting a few more to post in the future, but my bag of tricks
has been mostly laid bare on the site.

~~~
chaitanya
I submitted a tip a while back (a small reader macro trick for DO/DO*) --
don't know if you ever got it.

------
davexunit
Someone should make a Scheme tips site.

~~~
UNIXgod
I saw one in the form of a wiki awhile back. schemers cookbook maybe. The
venerable (lambda-the-ultimate) and readscheme still excellent. We can always
use more lisp and scheme oriented sites.

------
mck-
Here's a SLIME tip I recently found out:

C-c I -- this will give you an inspector that is much better than using
(inspect foo)

