This is a pretty cool project.
You can get around some of that by using a php accelerator but it would seem to me that something like that ought to be part of the basic distribution.
PHP already powers three of the top 10 websites. What was left to prove?
Where do you read that ? He's not making any suggestion of the kind, he's simply happy that PHP is not always scoffed on, and this piece of code is a really good example of what you can do when you use PHP properly. That comment could apply to plenty of other PHP projects. HN has a bit of a history of ridiculing PHP and the people who program in it.
> I don't agree.
With who ? Your strawman ?
The LISP here is a neat little stepping stone, just like almost any other 'language X implemented in Y' it is not currently meant as either a high performance solution or a production ready environment, just a neat little hack, easy to understand.
If you're in front of a river and someone builds you a rope bridge across you don't complain about the fact that it won't handle 6 lanes of highway traffic, you're just happy someone took the time and trouble to build it. If you don't want to use the bridge then fine, if you do then it's great.
What's left to prove is that there is a wrongness in the attitude towards certain classes of languages. I think PG is partly to blame for this with his 'blub' classification of programmers and languages. As though those that program in language X are somehow better than those that don't.
To tie LISP and PHP together in this way shows that that argument holds no water at all, and for some that may change their minds, which is good.
The naming of library functions alone can drive you bonkers. It's rare that I have to look up the names of functions in languages that I've used for a decade or more, with PHP it still happens with some regularity.
I know I could use an IDE to mitigate that but for some reason IDEs and me don't get along, with the exception of Borlands C Builder, which was really pretty good.
Well, of course, it uses a sandbox environment.
Question: Why does it have T, NIL, #T and #F? what roles do these symbols play in the language; which ones are canonical truth values, which ones signify list termination, and which ones signify the empty value? This is the perennial Lisp question.]
Is this a jab at the Lisp tradition of compiled sublanguages?
A lame, wasteful little script to print out a TODO list ;-)
(defun map-print (item list)
(mapcar (lambda (x)
(format t "~a in ~a~%" item x)) list))
(defun permute (list)
(mapcar (lambda (x)
(map-print x list)) list))
(defun languages ()
(destructuring-bind (response headers body)
(when (= response 200)
(loop for line = (read-line body nil nil)
Do you want to see “bad” stack traces? Try Erlang. There is a language with truly obtuse stack traces.
For me that's the 'benchmark' of understanding a language, to be able to re-implement it.
edit: by the way, it's been more than two months, but there have been a lot of things done in that time that have nothing to do with programming.
I would recommend these to someone who wants to implement a functional or a Lisp language, going with nothing but basic systems programming knowledge.
Recommend prerequisites are the first 2-3 chapters of SICP, some familiarity with classic compiler construction (dragon book would do, skip the lexical analysis and parsing parts though; you wont need much of that for Lisp if you retool and existing lexer. But focus on function calling and stack discipline, lexical scope and variable visibility, and maybe learn how an Algol dialect implements runtime heap-allocation) some exposure to C and assembly, and healthy curiosity.
A suggested order might be: Ghuloum, Wilson, Dybvig, the uncredited "lisp-implementation.pdf" paper, Gudeman, Kelsey, then Shao (Shao might make a whole lot more sense if you read one of Andrew Appel's compiler books and dip a tiny bit into ML.)
I write `brave', because it implements Scheme using Haskell. And if you aren't familiar with either, the learning curve will be steep.
See http://research.microsoft.com/en-us/um/people/simonpj/papers... for some hints on writing a compiler for those (or just general amusement).
For instance, it seems to be like travelling back to the 80's just to have to live with the 'third element in the list containing the data about a person' instead of simply using person->name , I've gotten used to thinking in terms of symbols so much that I find it hard to go back to the kind of trickery that was 'normal' in say microsoft basic in the 80's because it lacked named elements in something akin to a struct.
There is a certain kind of elegance in something so minimal but it also comes with considerable mental overhead and opportunity for mistakes.
Most people don't do that, except in throwaway code. In CL you can use an alist, a plist, a struct, or CLOS.
I've gotten used to thinking in terms of symbols so much that I find it hard to go back
Given that Lisp's history with symbolic computing goes back to the beginning, something about that doesn't sound right.
Your person->name comment reminds me of something, by the way. Portions of our app run in both CL and JS (via the Parenscript library). This is relatively easy, although there are a few disagreements between the two that you have to watch out for (such as how they handle null). Anyway, there are lots of CL features we've "ported" to JS via macros, but there is also one JS feature I found myself envying so much that I finally wrote a partial implementation of it in CL. That is JS's willingness to allow you to stick any property on any object just by setting it. It's a rather Lispy feature since it's maximally dynamic and maximally flexible. I find it handy for incremental development. When you have some data about a thing that you want to associate with it, but only some of the time, it's a real pain to have to make a separate data structure to hold it and then make sure it gets passed alongside the original thing to all the appropriate places. Our CL implementation of this is pretty crude but it allows the important thing, which is that you can write (@ something :some-data) and (setf (@ something :some-data) "blah") pretty much wherever you want. So we can be said to have Greenspunned a bit of JS in Lisp!
name age occupation) => PERSON
(make-person :name "Kris Kringle"
:occupation "Santa") => #S(PERSON-1)
(person-name *) ==> "Kris Kringle"
Don't worry, I realize that :)
> very real Lisp worth using has structures and objects:
That's a tricky and somewhat circular definition.
If it is worth using it is probably real and vv, but most lisp tutorials that teach 'pure' lisp do not have structures and / or objects, they rely on lists alone as their major data structure.
That also defines all lisps that do not have these items as somehow not real and there seem to be a lot of lisp people that somehow consider this 'impure'. Or is my reading material that dated ?
Go far a modern Lisp like Scheme. (You can ignore the syntax you don't want to deal with, yet.)
Usually it goes the other way around: you implement lists on top of defstruct.
But there is a danger in overusing structs and classes, too. You end up with these hugely complex ontologies for every little program, and frequently when you try to reuse code you end up with conflicts.
(car (cdr (cdr (cdr list))))
(at list 3)
The bigger problem is in code that consumes the lists item by item, every time an extra copy of the remainder of the list will be made, there it is much harder to work around this.
Very neat code by the way, thanks a ton for making this.
I'll be playing around with it for a bit, I've written a chunk of code for a small site a while ago in a 'functional' PHP style (as in, no assignments except at the highest level), I'll see if I can convert that project to your lisp dialect and get it to work.
You should even get rid of a custom type for Lisphp sequences and use PHP arrays directly. Ditto all other datatypes. Then if you use PHP's calling convention you should be able to call PHP code directly without needing USE and FROM, and more importantly PHP code can do the same to Lisphp with minimal pain. That way writing Lisphp libraries for others to use becomes viable.
Hint: via recursion, how do you advance along a sequence in a collection-agnostic way?
It is the ability to decompose an arbitrary sequential data structure efficiently that is important. It's not important because of any historical bias; it's important because it is incredibly useful.
If you can't support first/rest in an efficient manner, it is a bad sign.
It's important when you need to write your own iteration primitives. Map, fold, etc are all well and good, but sometimes they won't do because the iteration may require some unusual steps.
Or perhaps, what you're supporting is a "lispish" language that isn't really something we should directly compare to lisp, in the vein of Nu?
This is map:
(defun map (fn arr)
"Call FN on each element in ARR and return the returned values in a new array."
;; In newer versions of ECMAScript, this may call Array.map, too
(let ((idx 0)
(dolist (el arr)
(setf (aref result idx) (fn el))
(setf idx (1+ idx)))
This is reduce:
(defun reduce (func list &optional init) ;; the use of init here is actually a bit broken wrt null
(do* ((i (if init -1 0) (1+ i))
(acc (if init init (elt list 0)) (func acc (elt list i))))
((>= i (1- (length list)))))
Thanks for introducing me to Nu btw. What makes you say that it is not a Lisp?
This is map: http://github.com/dahlia/lisphp/blob/81849070ac7ff13948786b5...
This is filter: http://github.com/dahlia/lisphp/blob/81849070ac7ff13948786b5...
This is fold: http://github.com/dahlia/lisphp/blob/81849070ac7ff13948786b5...
Lisphp respect the iterator protocol of PHP instead of Lisp tradition in the practical reason.
Uh, constant-time insertions?
Of course, because of the whole shared hosting thing you'd have to fall back to a pure PHP implementation if the extension isn't loaded.
LispHP seems to use ArrayObject, though I'm not really sure how its performance is (googling indicates iteration is slow).
It's kind of moot because if speed were a huge concern, this might not be used in the first place, but just it would be interesting to see how far such a thing could be taken.
Please correct me if this is false.
At least this would solve the whole "which server should I use for lisp" problem...
He seems to have done (much) more than a half baked job of it judging by the rest of the page.
It says a lot about about his work that I am very excited to hack on it for the rest of the day, and I am not easily impressed by toy Lisps :-)
Tip of the hat to the author for doing the right thing, imo.
Also it's actual code, as opposed to most 'hacker news 'news''.
Does PHP lack for good libraries? That was the trick Clojure used with Java to get bootstrapped.
I guess if you were allowed to run compiled binaries you could just as easily use another Lisp, though -- except maybe if you needed to integrate with existing PHP applications. That might be a good use case.
> Does PHP lack for good libraries?
Yes. PHP's libraries are one of the ugliest and non lispy in existence :(
PHP is about as declarative as you get, assignments are the norm, not the exception and side-effects are how just about everything is done. It's not exactly elegant, but it fills a niche and apparently fills it quite well.
Though python is catching up, and even if it isn't quite as easy to deploy a large scale python web application as it is to deploy PHP the difference is getting smaller all the time.
As of 5.3 (and I won't say prior to that because even I don't believe it), PHP has become a nice utility language for just more than serving out wordpress.
Closures and the reference sweep GC level the playing field.
Building a Lisp on top of PHP strikes me as a vehicle for helping developers to adhere to the "good parts." I'm not sure whether that was the intent here, but it could turn out to be a useful side effect.
A note on the language itself:
It appears that you can choose any set of matching braces that you want anywhere in your program. I think this is the convention Scheme uses. Common Lisp reserves braces other than () for reader macros.
I personally, however, favor Clojure's approach of defining distinct behavior for each brace type. There are only three pairs of matched characters on the keyboard. It seems to me that this makes them too valuable to not leverage them as a core part of the language. Immediately knowing the meaning of a specific brace type makes it much easier to read someone else's code.
I have seen quiet a few PHP bashing comments recently that while true of older versions are much less true of 5.3, I mean there is still the same old nitpicks about the parameter orders and the amount of built in functions in the standard namespace but it is defiantly heading in the right direction.
An embedded lisp, even a slow and imperfect one is a nice stepping stone to have though.
It takes away two thirds of the trouble you have to go through when starting with a new language, environment and libraries.
$env = Lisphp_Environment::full();
$program = new Lisphp_Program("(echo 1)");
$env['echo'] = new Lisphp_Runtime_PHPFunction(create_function('', '
$args = func_get_args();
foreach ($args as $arg) echo $arg;
$env = Lisphp_Environment::full();
Which implements Lisp on Perl.
Join us if you are interested in this project!
have a few drinks
nine months later, baby arrives and uploaded to GitHub! :)