Only in Lisp

Discussion of Common Lisp
Gerenuk
Posts: 6
Joined: Thu May 13, 2010 6:17 pm

Only in Lisp

Post by Gerenuk » Thu May 13, 2010 6:31 pm

A friend of mine strongly recommends learning Lisp. It could actually be useful for my algebra program.
Now it takes a long time to learn a new language. I've read many comparisons, but most of them don't get to the point apart from mentioning performance issues. To me Lisp seems like a normal language like Python, with the only difference that Lisp is very hard to read.

So can someone enlighten me with a simple data handling example (no special syntactic tricks) which one cannot translate 1-to-1 to Python?

I can vaguely guess the Lisp syntax and all little programs I've seen seem to be convertable to any language. I would really like to see Lisp's advantage as concrete code.

nuntius
Posts: 538
Joined: Sat Aug 09, 2008 10:44 am
Location: Newton, MA

Re: Only in Lisp

Post by nuntius » Thu May 13, 2010 8:54 pm

Once you learn lisp's prefix notation, you will love its simplicity. Find an HP calculator buff to see how RPN lets them write simple tools to automate tasks. [Anecdote: For prob & stats homework, I spent a half hour writing RPN macros while my friend bashed keys on his TI. I then finished my homework in ten minutes, while he was less than halfway through.]

Same thing applies to prefix. The regular syntax makes it easy to write tools that rewrite your code.

Rewriting code is a common thing to do (its the core function of every compiler or interpreter); but most languages make it hard for the "normal programmer" to rewrite code, hiding the ASTs in deep internals.

Why would you want to write your own code-writing tools? Same reasons the compiler guys recommend you use a "high-level" language in the first place. Avoid boilerplate, write custom optimizers, automate patterns into "language features" (e.g. build looping operations out of conditionals and jumps), cross-platform abstractions, etc.

I don't know enough Python to clearly distinguish between its actual limitations and my shallow knowledge.

Would the following simple macros be easy to write in Python?

Code: Select all

(defmacro computed-jump (value &body body)
  (append
   `(case ,value)
   (loop for i from 0
      for clause in body
      collecting (list i clause))))

;; Example:
(computed-jump (random 3)
  "hi" "bye" "what")
; expands at compile-time to
; (CASE (RANDOM 3) (0 "hi") (1 "bye") (2 "what"))
; at runtime, randomly evaluates one of the three strings (simply returns the value)

(defmacro one-of (&body body)
  `(computed-jump (random ,(length body)) ,@body))

;; Example:
(one-of "hi" "bye" "what")
; expands at compile-time to
; (COMPUTED-JUMP (RANDOM 3) "hi" "bye" "what")
; which expands as above

;; Example:
(one-of (print "hi") (* 3 4)) ; might print "hi" or return 7

nuntius
Posts: 538
Joined: Sat Aug 09, 2008 10:44 am
Location: Newton, MA

Re: Only in Lisp

Post by nuntius » Thu May 13, 2010 8:56 pm

BTW, powerful tools often seem clumsy for simple tasks. Hence the difficulty in making a compelling "toy example".

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Only in Lisp

Post by ramarren » Thu May 13, 2010 10:42 pm

Gerenuk wrote:To me Lisp seems like a normal language like Python, with the only difference that Lisp is very hard to read.
I, for one, find Lisp code much easier to read than any other programming language, since it can usually be actually read, with punctuation serving similar role as punctuation in prose, rather than syntax being the primary determiner of meaning. This is obviously extremely subjective. Editing Lisp code is also much easier thanks to Emacs capability to semi-structurally edit nested symbolic expressions.

Of course the syntax allows effective macros, but since they are compiler customizations they are not that important if you don't care about having a compiler in the first place. Although the ability to add new control constructs at language-user level is still useful, for example: if someone does not like the built in language iteration construct, they can add a new one, and in fact there are at least two major ones: iterate and series. In Python or most anything except languages derived from either Lisp of Forth this would only be possible by language developers or front-end preprocessing.

And there are features unrelated to syntax. For example, Common Lisp Object System, especially combined with a metaobject protocol. Optional static typing. There is a list of some of those with explanations here.

Gerenuk
Posts: 6
Joined: Thu May 13, 2010 6:17 pm

Re: Only in Lisp

Post by Gerenuk » Fri May 14, 2010 8:08 am

Sure, the prefix notation is simple and universal. A mathematician would love the consistency. I just find it unnatural, so for me it doesn't help if Maths like the notation. I rather want to it to match with natural reasoning. But anyway, this is not the topic here (but I appreciate links to webpages with comparisons!)

Here I would only like to discuss written out examples. Is there anything about data treatment that makes Lisp superior (to another scripting language like Python)? I'm aware of the huge performance gap, but now I'm also interested in the methods.
Maybe even someone knows an advantage for my specific case: I want to store mathematical expressions (with + * and variables) as trees and manipulate them according to arithmetics.

In order to understand the difference, I tried to replicate the Lisp example in Python. It conceptually slightly different, but doesn't it work just as good?
Maybe someone can point out the differences.

Code: Select all

from random import randrange

def computedJump(value, *commands):
  return commands[value]
  
def oneOf(*commands):
  return computedJump(randrange(len(commands)),*commands)

print computedJump(randrange(3),"hi","bye","what")   # result needs to be printed

def p():
  print "hi from p"

print oneOf(p,3*4)  # of course here one needs to decide beforehand whether you want to execute the function or use the result as data; you could do both but then you need 5 more lines to define a new class thats flexible
Btw, in Python you also have iterators and generators if that is what you mean by "iterate and series". Basically it's a function which when called "yield"s a return value and the next time it is called, it *continues* after the last yield statement and possibly loops again to yield the next value.

PS: so I know scripting languages are good, but why is anyone of them better than the other? ;)

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Only in Lisp

Post by ramarren » Fri May 14, 2010 8:39 am

Gerenuk wrote:Is there anything about data treatment that makes Lisp superior (to another scripting language like Python)?
Common Lisp is not really a scripting language. That term is rather nebulous anyway, but many strengths of Common Lisp only become apparent with large programs, where you can build up the language to the problem domain. For one-off scripts a good standard library is more important, and since CL was standarized before huge "batteries-included" standard libraries became popular (not that it would have made it through ANSI comitee anyway) by today standards it is a very small language. Its reputation of being a huge language came from early nineties, when it was compared to languages of that time, especially Scheme.
Gerenuk wrote:Btw, in Python you also have iterators and generators if that is what you mean by "iterate and series". Basically it's a function which when called "yield"s a return value and the next time it is called, it *continues* after the last yield statement and possibly loops again to yield the next value.
But my point was that those things in Python had to be added by language developers, who had to modify the intepreter and so on. In Lisp those are userspace libraries written in pure Lisp.
Gerenuk wrote:Maybe someone can point out the differences.
You noted the difference in the comment: in Lisp you can just expand to needed code. In Python you would need a boilerplate to create a function object, and then pass this object around. The point of one-of is that only one branch is executed, which is important if they are either side-effecting or expensive. The crippled lambda and statement/expression division in Python alone are enough for me to strongly prefer Lisp over it.

Of course for small examples the gains are small, which is a problem with small examples. And bigger examples are incomprehensible without context.

Jasper
Posts: 209
Joined: Fri Oct 10, 2008 8:22 am
Location: Eindhoven, The Netherlands
Contact:

Re: Only in Lisp

Post by Jasper » Fri May 14, 2010 8:54 am

Never mind this, but imo 'natural reasoning' doesn't really have too much to do with how you denote it, and how mathematicians denote things isn't always particularly natural. Edit: It's convenient on paper and such, but it remains just notation.

One feature that doesn't seem mentioned enough is special variables is a pretty awesome feature, allowing you to 'function-ize' a program, for one. Seems like a comparatively easy one to implement, weird that other languages don't seem to be interested in doing so. CLOS is probably a lot better than whatever Python has, but i must admit i don't know what Python has :)

One could make macros to make it look more like math, or even just a new filetype. Since lispers very often seem to use macros that are in a subset, with functions, this could probably save a bunch of parenthesis. The problem that it is too easy to do so, many lispers don't like it and one would probably want consensus about it.

Maybe a superset-of-Python notation-wise. Or ML-like notation. A potential problem with polish notation and CL is that CL has functions and variables in different namespaces, the reader can't always see the difference. But CL users are nearly always in the subset where it won't cause problems; they use *special-var*, +constant+, and macros attaching to values variables allow you to set the variable name. Slot values could be a bit of an issue, but a macro can be made for that too.

I think that is a good idea, it would help get people to CL and as they'd 'meet' macros they'd be lured into macros anyway, and even otherwise, Lambda and Funcall be strong.

Btw, about iterating/collecting there are rather many ways we do stuff like that.. There is libraries Iterate, Series, Loop(attached to CL), there is using (tail-)recursion, there is using higher order functions, there is using callbacks with accumulation macros.. Not many lispers use iterators as in objects you can move forward with a 'next' function and backward with a 'previous' function or anything like that.

gugamilare
Posts: 406
Joined: Sat Mar 07, 2009 6:17 pm
Location: Brazil
Contact:

Re: Only in Lisp

Post by gugamilare » Fri May 14, 2010 11:43 am

Lisp makes you think about the problems in a different way. In general, when a Lisper wants to solve a problem, he tries to abstract and solve the entire kind of problem instead. It gets an amount of time to understand this.
There is one thing I managed to do which is either annoying or not easy to do in other languages. I wanted to store dynamically created functions into files, including closures. Functions are first-class values in lisp, they can be created by other functions, passed around in variables and called the way you want. Closures are functions with a free variable, like this:

Code: Select all

(defun make-adder (n)
  (lambda (m)
    (+ m n)))

cl-user> (defvar func (make-adder 30))
func
cl-user> (funcall func 10)
40
cl-user> (funcall func 24)
54
Which are, by the way, very useful programming tools.

I managed to this by creating macros that are intended to substitute lambda and let (among others). The macros then "remember" the free variables and the code from functions, which are taken and stored into files whenever you ask to store a function.

Now, there are a couple of ways you would do it in, e.g., Python:
  • Instead of creating the function you want to create, you would create a string with the code, which then is passed to another function that "remembers" it and sends the code to the interpreter so the interpreter would create the function, which is then returned.
  • Create a small interpreter that revolves around the functions you want to use.
The second solution is obviously painful. The first get trickier as you want to associate the function with the free variables, and also remember which free variables are shared among which functions. It would be so strange to deal with such a thing that you probably would give up and find another solution to do what you want with your program.

In any case, like everything in the world, you might like Lisp or not. The only way to know is learning.

lithos
Posts: 14
Joined: Tue Feb 02, 2010 4:11 pm

Re: Only in Lisp

Post by lithos » Fri May 14, 2010 12:00 pm

There is no such thing as "Only in X language". By default all programming languages are the same in the sense that they exist to solve problems, they're only different when you actually use them.

I've picked up an interest in lisp because it offers more tools than other languages to get away from scripting languages. And ways to do the same amount of "stuff" with less code(at least during development periods).

Gerenuk
Posts: 6
Joined: Thu May 13, 2010 6:17 pm

Re: Only in Lisp

Post by Gerenuk » Fri May 14, 2010 6:19 pm

Ramarren wrote: But my point was that those things in Python had to be added by language developers, who had to modify the intepreter and so on. In Lisp those are userspace libraries written in pure Lisp.
That's absolutely true - before iterators/generators were introduced there was a really useful part missing. But OK: can you think of a feature that isn't implemented in Python yet?
Iterators and generators are, but beyond that there isn't much special. So is anything missing in Python?
Ramarren wrote: You noted the difference in the comment: in Lisp you can just expand to needed code. In Python you would need a boilerplate to create a function object, and then pass this object around. The point of one-of is that only one branch is executed, which is important if they are either side-effecting or expensive.
Hmm, I need to think about that. But true, it wasn't so straightforward for me to translate the Lisp example.
Ramarren wrote: The crippled lambda and statement/expression division in Python alone are enough for me to strongly prefer Lisp over it.
What's crippled? You mean you cannot put commands in the lambda? So far it seemed fine, because as soon as your lambda is so big as to include statements, you rather write a full function definition. "def f():" isn't that much to write.
Jasper wrote: One feature that doesn't seem mentioned enough is special variables is a pretty awesome feature, allowing you to 'function-ize' a program, for one.
I'd highly appreciate real, short examples in this thread. I hardly know enough Lisp to make up my own, but I can guess what example code means. Can you write out an example, which cannot easily be replicated with Python?
gugamilare wrote: Now, there are a couple of ways you would do it in, e.g., Python:
I'd say there is only one straightforward way.

Code: Select all

def makeAdder(n): return lambda x:n+x
For more complex task you can use

Code: Select all

def makeFunc(a):
  def Func(x):
    return x+a
  return Func
I never understood why it works and where it stores the variable "a", but it does work!
gugamilare wrote: In any case, like everything in the world, you might like Lisp or not. The only way to know is learning.
I have my own opinion about style and beauty of expressions.
In this thread I merely want to examine one particular facet, namely "what is example code, that shows functionality differences to python?".
As with the first Lisp example, I cannot fully translate the way to intermix code and data, but it seems I can write a program just as short and clear which has the same functionality.

Post Reply