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.
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
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.Gerenuk wrote:To me Lisp seems like a normal language like Python, with the only difference that Lisp is very hard to read.
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.
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
PS: so I know scripting languages are good, but why is anyone of them better than the other?
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:Is there anything about data treatment that makes Lisp superior (to another scripting language like Python)?
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: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.
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.Gerenuk wrote:Maybe someone can point out the differences.
Of course for small examples the gains are small, which is a problem with small examples. And bigger examples are incomprehensible without context.
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.
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
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.
In any case, like everything in the world, you might like Lisp or not. The only way to know is learning.
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).
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?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.
Iterators and generators are, but beyond that there isn't much special. So is anything missing in Python?
Hmm, I need to think about that. But true, it wasn't so straightforward for me to translate the Lisp example.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.
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.Ramarren wrote: The crippled lambda and statement/expression division in Python alone are enough for me to strongly prefer Lisp over it.
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?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 say there is only one straightforward way.gugamilare wrote: Now, there are a couple of ways you would do it in, e.g., Python:
Code: Select all
def makeAdder(n): return lambda x:n+x
Code: Select all
def makeFunc(a): def Func(x): return x+a return Func
I have my own opinion about style and beauty of expressions.gugamilare wrote: In any case, like everything in the world, you might like Lisp or not. The only way to know is learning.
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.