Lisp in Your Language
danthedev.com
danthedev.com
In all seriousness, I worked with a bright guy who was a lot of fun to work with, but every once in a while his exuberance for this sort of thing would find itself in code that other people had to read/maintain. One particular example, he implemented a small subset of Lisp encoded into PHP arrays and it was used throughout some test code.
He effectively proved you could write PHP in a Lisp style and that PHP programmers overwhelmingly hate PHP flavored Lisp.
(It's also worth noting that theme() hasn't worked this way since 2011; it now takes a more PHP-style associative array of named options.)
Before the bracket-syntax for arrays, this would have been awful to maintain.
>> Any sufficiently complicated C or Fortran program contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.
It also has some things CL doesn't provide as part of the language: threading primitives; URL-handling; advanced calendrical calculations; basic crypto and so forth.
Other than this, however, it's a good example.
The point is that low-level languages like C and Fortran (and today, Java) are underpowered, and any sufficiently large project will evolve to the point where someone builds a (often vaguely Lisp-like) scripting language on top of it to allow developers to raise the level of abstraction, maybe without even realizing that's what they're doing.
I have seen this in action, a lot of companies build internal, proprietary scripting languages on top of their low-level programs. They may start out as configuration files, a build system, preprocessor macros, or a DSL, but over time as features get added they accidentally become Turing-complete, and eventually someone writes an interpreter and now you've invented something that serves the same purpose as Lisp, only worse.
More here: https://sites.google.com/site/steveyegge2/the-emacs-problem
No, that's not what it is about. It's not about programs needing a scripting language.
It's about the program (its framework, libraries, architecture, ...) itself. It will acquire features like:
* late binding
* symbols
* dynamic data structures
* serialization format
* a plugin architecture with loading of code
* advanced error handling
* first class function objects
* automatic memory management
* specialized numeric datatypes (large integers, ...)
* a dynamic object system
* more...
The implementation language will be extended by some framework, software layers, libraries with such features ... so that over time it will implement many of the standard features of Common LispNote that platforms like the JVM, .net and others nowadays provide many of that (and much more). Also language on top of those do: Java/Scala/... See for example how for Java dynamic loading of code has been implemented on top of custom class loaders.
https://github.com/pusher/pusher-js/blob/2.2/src/defaults.js...
parser in https://github.com/pusher/pusher-js/blob/2.2/src/strategies/...
The main reason was that we were thinking about helping clients with server-supplied connection strategies. We could gather some metrics and tell the client in advance that, for example, WebSockets won't work due to some network issues. We also thought it could be useful for orchestrating migrations and working around potential load balancing issues. Injecting JavaScript was out of question, so I wrote this JSON DSL for connection strategies.
We haven't done that and it's probably never going to happen. The Internet has moved on, we dropped support for some ancient browsers, connectivity has improved and we haven't really felt a need for that feature, to be honest.
I agree that at the moment it's unnecessary.
I was originally in a team of 4-5 programmers, but the company slowly got rid of everyone except me. At that point I tried to leverage the situation and institute some changes in the programming languages, web stack and workflow automation; most of them were rejected by the boss on the grounds like "sure, we could switch to something better - like say, Ruby - but Ruby programmers are much more expensive than PHP."
It took me a lot of work and pain to eventually leave. My two biggest mistakes:
1) Not noticing when was the best time to go. There was a moment when the old project ended and they wanted to get me into a next one. Building it solo. From scrapped bis of metal. I should have left right there.
2) Being too afraid of changing jobs. I know that with my skills I can land a new programming job very quickly, but the process of job interviews scares me.
Oh, and 3) Singing that exit-level contract that ended up with me working my ass off in the evenings to finalize some contracted components.
Job interviews are a nuisance, but easily trainable. :)
x=filter(a,lambda(({ 'o }),
({ (#'>),
({ (#'call_other),
({ (#'environment),'o }),
"query_level"
}),
WL_APPRENTICE
})));
[1]: https://en.wikipedia.org/wiki/LPC_(programming_language)(Disclaimer: I’m used to Lisp so I’m not really the audience whose opinion matters. But I’m sure I would’ve benefited from reading this earlier. Skimmed it, and am now halfway through a more careful read.)
Images can be great aids in understanding text and making abstract concepts concrete. Also, in many cases the usual metaphor/simile rules apply. For instance, in the phrase he's "fast as a bolt of lightning" we can imagine the speed of the runner and it helps us envision how he "flashes" by opponents. In this case both concepts are known i.e. lighting and fast, but new descriptive meaning is created through the use of simile. Similarly, metaphor takes two known concepts and combines them to reveal a new concept. An example of metaphor, would be "he's an emotional rollercoaster", we know what emotional is and how a rollercoaster behaves, this gives us new insight into the persons high and low spiraling personality.
Essentially, I think good images interact just like simile and metaphor with a text, enhancing, extending, and clarifying concepts. If you go back now and look at your images, I think you'll see that they actually reflect rather verbatim what the text contains, only minimally extend or clarify the text, and at times might make it more confusing (how do turtles enhance our understanding of expressions?). So for these reasons, I found them to be distracting and not helpful, as nice as they actually appear graphically :)
Nice post btw :)
There is something special about special forms. A basic set of special forms is needed and can't be implemented as macros.
It doesn't have to be built into the language; it could be a macro based on COND or even on WHEN/UNLESS. But…
> A basic set of special forms is needed and can't be implemented as macros.
One has to have some special forms in order to build everything else as macros. And in practice, of course, there can be some big efficiency gains to having lots of special forms vice having only a few and lots of macrology.
In Common Lisp IF is built in and COND is a macro. One of the conditionals needs to be built-in.
http://www.lispworks.com/documentation/HyperSpec/Body/s_if.h...
> One has to have some special forms in order to build everything else as macros.
For conditionals, one conditional needs to be there, into which the other macro-based conditionals can be expanded.
> And in practice, of course, there can be some big efficiency gains to having lots of special forms vice having only a few and lots of macrology.
Not really. Common Lisp has a minimum of special forms and usually has some of the faster Lisp implementations.
That's actually not true. IF can be implemented in terms of LAMBDA.
(defun _true (then else) then)
(defun _false (then else) else)
(defmacro _if (condition then else)
`(funcall (funcall (function ,condition) (lambda () ,then) (lambda () ,else))))
? (_if _true (print 123) (print 456))
123
123
? (_if _false (print 123) (print 456))
456
456
?[UPDATE]
You have to make some minor tweaks to my original code to make it work. Here's a fully tested version:
(defun _true (then else) then)
(defun _false (then else) else)
(defmacro _if (condition then else)
`(funcall (funcall ,condition (lambda () ,then) (lambda () ,else))))
(setf (get t 'altboolean) '_true)
(setf (get nil 'altboolean) '_false)
(defun ->altboolean (condition) (get condition 'altboolean))
(defun _fact (n)
(_if (->altboolean (<= n 1)) 1 (* n (_fact (1- n)))))>> In Common Lisp IF is built in and COND is a macro. One of the conditionals needs to be built-in.
> That's actually not true.
The context was about Common Lisp, not Haskell nor Scheme (of course other languages do things as they wish, including lazy evaluation). There need to be at least one conditional built-in in CL in order to map generalized booleans to {T, NIL}. This conditional could even be eager, but there has to be a construct which selects the approprate value. Which of the other 24 special forms is suitable?
As implemented, it's not quite a drop-in replacement for IF, but it can be made so by rolling the call to ->ALTBOOLEAN in to the _IF macro.
> The context was about Common Lisp
Yes, I know that. The example code is written in Common Lisp.
> there has to be a construct which selects the approprate value
Yes. LAMBDA can do that.
> Which of the other 24 special forms is suitable?
LAMBDA. It can be used both to select the appropriate value and to delay evaluation. LAMBDA is really all you need. Making IF a special form is just an optimization.
> LAMBDA.
I am nitpicking, but LAMBDA is not a special form, FUNCTION/FLET/LABELS are: http://www.lispworks.com/documentation/HyperSpec/Body/03_aba...
> It's a pretty elementary exercise to fix ->altboolean so that this invariant is maintained.
And how do you map generalized booleans to your functions?
Right now, I can think of two possible ways. You can map NIL to #'_false in a hash-table, and use (gethash nil table #'_true) to provide a default value. Or you can also write a generic function:
(defgeneric ->altboolean (x)
(:method ((x null)) #'_false)
(:method (x) #'_true))
There could be other ways, but as far as I know, none of them are portable, because even though it is allowed for all defined CL operators to be implemented as built-ins, you generally cannot expect or assume that it is done so (see gethash in CCL and SBCL). As far as you know, and even though it would be terribly inefficient, they could all be implemented only by combining special forms.If you discard IF, can you perform the elementary exercise using only special forms? I cannot imagine how, but I honestly would like to be shown a working approach.
You certainly are.
> can you perform the elementary exercise using only special forms?
I don't even need any special forms. All I need to do is use the default argument to GET.
CL-USER 16 > (defparameter a 0)
A
CL-USER 17 > (if (foo) (foo) (foo))
T
CL-USER 18 > a
4
CL-USER 19 > (defparameter a 0)
A
CL-USER 20 > (_if (->altboolean (foo)) (foo) (foo))
T
CL-USER 21 > a
5
Given that foo is defined as: (defmacro foo () (incf a) '(progn (incf a) t))
4 vs. 5Does not look like a true replacement for IF in Common Lisp...
I'm not talking about Lambda Calculus and related.
I'm talking about Lisp implementation. Real world Lisp implementation.
(Also note that Lisp macros don't have to be all written in Lisp. They are just expander functions. When you're bootstrapping a Lisp, you can write macros in the bootstrapping language. So the chicken-and-egg problem of "how do you write the first macros if there are no special forms" doesn't exist. You write the raw functions in assembly, or C or whatever, and register them as macro-expanders.)
[0] : https://github.com/kanaka/miniMAL [1] : https://github.com/kanaka/mal/tree/master/miniMAL [2] : https://github.com/kanaka/mal
Hy does this for Python (except that its initial implementation started from a parser). It essentially becomes a syntax for manipulating Python ASTs as plain old data-structures instead of classes with terrible interfaces. It's actually a great way to become intimate with the inner workings of your host language.
It's funny how far you can get by sprinkling a few parentheses around.
https://github.com/smizell/geneva
It is Lisp in JSON. I did it for fun, but thought it would a cool way to send instructions across the wire from the server to the client and back. Imagine validation rules that could be ready in any language with really very little parsing instructions.
https://github.com/refractproject/refract-spec/blob/master/r...
We use it very similarly to how you would with Lisp, where the "element" may be a function of sorts.
Still, seems very accessible and useful to people who don't feel like going through the trouble of learning/building a "real" lisp but will read a blog post.
I guess programmers of those languages must desperately want to escape to another language.
My solution is going to be turning these rules into something that looks like Python, and feed each line to eval(). I reckon that will make 90% of the rule evaluation engine, which is my brittler code, to just disappear.
Sometimes the most obvious choice is also the best.
No, none of these rules are input by users. All of them come from our repo. We're safe and good.
Plumb is certainly not a Lisp though; it's actually a syntax for lambda calculus with de Bruijn indices, which just-so-happens to embed easily in common scripting languages (PHP, JS, Python, etc.).
Keep them coming.
For some of us, every week is Lisp week grin