
Lisp in Your Language - codecurve
http://danthedev.com/2015/09/09/lisp-in-your-language/
======
steego
Oh noes! Don't give people these bad ideas! :)

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.

~~~
daniel-levin
Greenspun's Tenth Law [0] is a humorous aphorism that applies here.

>> Any sufficiently complicated C or Fortran program contains an ad-hoc,
informally-specified, bug-ridden, slow implementation of half of Common Lisp.

[0]
[http://c2.com/cgi/wiki?GreenspunsTenthRuleOfProgramming](http://c2.com/cgi/wiki?GreenspunsTenthRuleOfProgramming)

~~~
GFK_of_xmaspast
What would be some recent examples of this. (In the spirit of generosity I
will accept a substitution of c++ for c and a reasonably-fortranish language
for fortran).

~~~
TeMPOraL
Scala the language ;). Or every time someone reinvents "programming in XML"
(and yes, so-called "behavioral trees" in game development, at least in their
basic form, also count).

~~~
GFK_of_xmaspast
How is scala a large c-ish or fortran-ish project?

~~~
kyllo
Greenspun's Tenth Rule is a joke (there aren't even any other rules numbered
1-9). It's not meant to be taken literally.

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](https://sites.google.com/site/steveyegge2/the-emacs-problem)

~~~
lispm
> will evolve to the point where someone builds a (often vaguely Lisp-like)
> scripting language

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 Lisp

Note 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.

------
codecurve
Author here, would be interested to hear people's take on the addition of
illustrations (illustration is being generous, I know). Do you find them
distracting or do they help break up the text?

~~~
davexunit
I think they are nice. I think you made the basic ideas behind Lisp accessible
and fun. Good job!

~~~
calibraxis
I agree! Lucid approach. The illustrations work for me. I like the approach of
using eval immediately, without ceremony.

(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.)

------
lispm
IF is not a function. Functions don't evaluate their arguments. Functions
actually get evaluated arguments passed. But IF is a special form, built into
the language. Special forms are not functions.

There is something special about special forms. A basic set of special forms
is needed and can't be implemented as macros.

~~~
zeveb
> But IF is a special form, built into the language.

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.

~~~
lispm
> It doesn't have to be built into the language; it could be a macro based on
> COND or even on WHEN/UNLESS. But…

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...](http://www.lispworks.com/documentation/HyperSpec/Body/s_if.htm#if)

> 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.

~~~
lisper
> One of the conditionals needs to be built-in.

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
        ?

~~~
ClashTheBunny
There are problems with infinite recursion if you do that, no?
[http://stackoverflow.com/questions/1171252/whats-the-
explana...](http://stackoverflow.com/questions/1171252/whats-the-explanation-
for-exercise-1-6-in-sicp)

~~~
lisper
Nope. That's the reason for wrapping THEN and ELSE inside lambdas, to delay
the evaluation until after one of them is selected. Try it.

[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)))))

~~~
junke
Does "fully tested" means it is supposed to work as a replacement of IF in
Common Lisp? Or is it just a toy example in a made-up Lisp/Scheme to beat that
dead horse?

>> 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?

~~~
lisper
Fully tested means that it solves the problem of infinite recursion cited in
the stackoverflow question.

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.

~~~
lispm

        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. 5

Does not look like a true replacement for IF in Common Lisp...

~~~
lisper
4 and 5 are both correct results. Implementations have a lot of flexibility
regarding when macro expanders are called.

------
roblabla
This is very similar to miniMAL [0]. They even have a miniMAL interpreter
written in miniMAL [1] in the Make a Lisp project [2].

[0] : [https://github.com/kanaka/miniMAL](https://github.com/kanaka/miniMAL)
[1] :
[https://github.com/kanaka/mal/tree/master/miniMAL](https://github.com/kanaka/mal/tree/master/miniMAL)
[2] : [https://github.com/kanaka/mal](https://github.com/kanaka/mal)

------
agentultra
You could also take your proto-eval and spit out ASTs into your favorite
language for your given special forms and bootstrap a new interpreter from
there.

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.

------
undershirt
If JS developers want a concrete example of Lisp's benefits, you only need to
look at React's JSX syntax-- it lacks conditional logic and loops. To see why,
you kinda have to see how React components are created in ClojureScript's lisp
syntax, it's really elegant: [https://github.com/shaunlebron/jumping-from-
html-to-clojures...](https://github.com/shaunlebron/jumping-from-html-to-
clojurescript)

~~~
davexunit
I think JSX is just terrible, glad to see someone else feels the same. The
ClojureScript way is much better, though I think SXML style is best:
[http://okmij.org/ftp/Scheme/SXML.html](http://okmij.org/ftp/Scheme/SXML.html)

------
smizell
I wrote a very similar tool one time:

[https://github.com/smizell/geneva](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.

~~~
smizell
We're also working on a data format that allows for this use of arrays.

[https://github.com/refractproject/refract-
spec/blob/master/r...](https://github.com/refractproject/refract-
spec/blob/master/refract-spec.md#compact-format)

We use it very similarly to how you would with Lisp, where the "element" may
be a function of sorts.

------
ekmartin
Creating a Lisp is a great way to learn a language.
[https://github.com/kanaka/mal/](https://github.com/kanaka/mal/) has thorough
tests and step by step instructions to help you along the way, definitely
recommend checking it out.

------
mordocai
Very good post but ewwwww to the way you have to implement it in Javascript.

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.

~~~
zeveb
Well, once you've got this much going all you need to implement is a proper
READ, and then life is just about perfect.

------
eru
Compare
[https://en.wikibooks.org/wiki/Write_Yourself_a_Scheme_in_48_...](https://en.wikibooks.org/wiki/Write_Yourself_a_Scheme_in_48_Hours)
for Lisp in Haskell.

------
bliti
One of these days I'm going to stumble into something like this in a project.
Probably written in Delphi or VB.NET. Not that I use those languages, but it
tends to be that the weird stuff tends to appear there. At least for me.

~~~
jimbokun
"Not that I use those languages, but it tends to be that the weird stuff tends
to appear there."

I guess programmers of those languages must desperately want to escape to
another language.

~~~
kitd
So a Lisp in VB is like fingernail scratches on an old prison cell wall? I
like that analogy!

------
candeira
I'm working on a data validation pipeline, and I recently noticed that the
rules in my jury-rigged rule engine already look a bit like lisp, and briefly
considered embedding a tiny scheme. That consideration lasted about a
coffeetime.

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.

------
chriswarbo
I've made an embedded language called Plumb, which works along similar lines:
[http://chriswarbo.net/essays/plumb](http://chriswarbo.net/essays/plumb)

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.).

------
latenightcoding
Lisp articles have been making their way to HN's 1st page the whole week.

Keep them coming.

~~~
nkassis
Maybe we can designate this week as Lisp week every year where we revive our
collective love for the language. Sure beats shark week in value.

~~~
zeveb
> Maybe we can designate this week as Lisp week every year

For some of us, _every_ week is Lisp week _grin_

~~~
TeMPOraL
And others only dream that maybe their grandchildren will live such happy
times as their grandfathers did. But it's time to go to bed, get some sleep
before another day of reimplementing half of CL in Java...

~~~
DonaldFisk
[https://xkcd.com/297/](https://xkcd.com/297/)

