
Picolisp - qwertyuiop924
http://picolisp.com/wiki/?home
======
eggy
Check out the RC Simulator the creator programmed many years ago in assembler.
It's all pixel pushing, no OpenGL, and no texture mapping, but still
incredible. I posted about it on HN a year ago too [1,2].

Work has been done to run it on bare metal too - a sort of LISP Machine in
PicoLisp!

[1] [http://picolisp.com/wiki/?rcsim](http://picolisp.com/wiki/?rcsim)

[2]
[https://news.ycombinator.com/item?id=9954773](https://news.ycombinator.com/item?id=9954773)

------
allendoerfer
I love how everything is pico until these Java namespaces come along and crash
the party.

I think it should make it clearer whether you can actually use this and how.
It seems to be run inside a VM and call C and Java functions. They advertise
this prominently, but having to run both Picolisp and JVM does not seem very
attractive to me. Can we use it reasonably without Java? Is it production
ready? How fast is it? How old is it?

I think a programming language is hard to sell, so they should work on that a
bit (if that's there goal, of course).

~~~
eggy
The standard PicoLisp is not java-based or VM bound; there is a java
implementation called Ersatz [1] that is older, and is there just for the Java
hook. It is smaller than Lua considering how much is built-in

PicoLisp is written in C, or the 64-bit version in assembler. It is Posix-
dependent, so you need to run it in Cygwin for Windows, although somebody is
working on a platform independent version based upon Midipix to eliminate the
Posix dependency [2].

The creator of PicoLisp, Alex Burger, created it for his own use decades ago.
It has a built-in database and Prolog interpreter. It is very fast for an
interpreted Lisp, and there are lots of examples on rosettacode.org.

It is fexprs-based instead of sexprs as far as I know.

I like it a lot, but since I am on Windows for my livecoding / game dev hobby,
I have not gone too far with it. I am hoping the Midipix work takes off. I
also run Linux on my notebook, but all of my work nowadays is on Windows. .NET
Core might change that.

Most games still run on Windows, and the ones on Linux have compatibility
issues across the various Linux distros.

There may be a glowing white Apple on most web-dev's notebooks, but my 3 year
old Alienware plays games with a Technicolor LED show that would put the F&F
film franchise to shame ;)

[1] [http://picolisp.com/wiki/?javacode](http://picolisp.com/wiki/?javacode)

[2] [http://midipix.org/](http://midipix.org/)

~~~
qwertyuiop924
>It is fexprs-based instead of sexprs as far as I know

...I don't think that was what you meant.

Picolisp _has_ fexprs, and it uses them quite a lot, but they replace macros,
not sexprs.

~~~
eggy
You're right. Thanks for catching that incomplete sentence/thought. It uses
fexprs in place of macros.

I had been reading John Shutt's paper a day before this post, on what he calls
vau calculus vs lambda calculus, where the Kernel programming language is used
as an example implementation [1]. Very interesting take on fexprs given the
arguments raised around them.

[1]
[https://web.cs.wpi.edu/~jshutt/kernel.html](https://web.cs.wpi.edu/~jshutt/kernel.html)

~~~
qwertyuiop924
Well, Shutt's work is about doing analysis and optimizations to fexprs.
Picolisp essentially views compilers, analysis, and optimization as anathema.

~~~
eggy
Agreed. I am just struggling with Shutt's paper, but every now and then I get
an epiphany in my understanding, and so I keep reading on. I am basically
revisiting the old history of fexprs for my own education.

PicoLisp is pretty fast as an interpreted language, and holds a niche spot.
But then again, the creator built it up over the years for his own work. It is
very practical and compact when you use it in certain scenarios. I am
ambivalent about the way it mixes PicoLisp and HTML in the Canvas examples. It
cuts both ways to be that integrated.

Still, I always go back to play with it, because I just love how succinct and
logical the code is for a lot of typical programming chores. I tried doing a
game with it, but it was too much work (for me) to get it going cross
platform, or at least Windows aside from Linux. I don't like Cygwin at all.

~~~
qwertyuiop924
Yeah, you can have POSIX, or you can have cross platform: pick one.

Picolisp is interesting, but as a schemer, I wish it had TCO. Lexical scope
would be nice too: macros are hard enough to code, don't make us worry about
macro programming when we're not writing macros of fexprs.

------
tankfeeder
4clojure on PicoLisp
[https://bitbucket.org/mihailp/tankfeeder/src](https://bitbucket.org/mihailp/tankfeeder/src)

------
cmrx64
It's neat to see a "modern" web page and extensive documentation for such an
incredibly old piece of software. While hacking on some old computers (one of
my hobbies) I came across picolisp but never thought to look for it on the
web. I assumed it was dead, like a large portion of the rest of the software
on the box.

------
rubiquity
Hilarious introduction text.

------
overcast
That Share Tech Mono font gives me a headache.

~~~
squimmy
For a monospace font, the characters aren't nearly distinctive enough.

------
darkseas
Has the story for PicoLisp on OSX changed at all? My daily drive is El Capitan
and there were issues compiling the source because of Clang/gcc
incompatibilities last time I tried. Precompiled binaries were around but are
no longer linked I think.

~~~
shpx
I think it's been working for a long time, I just ran

brew reinstall --build-from-source picolisp

and it worked.

~~~
darkseas
Thanks, will try to hack the weekend away.

------
eyan
Long time fan. Great docs. And a 'native' Prolog interpreter:
[http://software-lab.de/doc/ref.html#pilog](http://software-
lab.de/doc/ref.html#pilog)

------
Grue3
(setq foo (1 2 3))

So how does evaluation work here? Why isn't (1 2 3) evaluated? Or is it not
evaluated because 1 is not a function? In which case, is it not possible to
create a literal list where the first element is a function?

~~~
marklgr
setq is called a 'special form', which does not evaluate its args as other
s-expr would.

~~~
masklinn
setq would in fact evaluate its second argument (and bind it to the name
specified by the 1st).

Picolisp has a special rule for (literal) lists starting with a (literal)
number, they're implicitly quoted instead of the CAR being interpreted as a
function:

> if the CAR of the list is a number, the whole list is returned as it is

This makes more sense considering a second quirk of Picolisp: numbers can be
used as functions, in which case they're interpreted as a pointer to the
executable code to run.

And from what I understand Picolisp's execution model doesn't have special
forms as such, rather function definition specifies whether they receive their
arguments evaluated or not.

~~~
qwertyuiop924
It also has macros now, but they're rarely used.

------
TheMagicHorsey
Racket has some of the same properties. But it lacks the performance and
simplicity. But with Racket you gain other things like more powerful macros,
an integrated environment, and perhaps more libraries.

~~~
qwertyuiop924
Racket is a little too complex for my tastes. It's a little too big, a little
to exerimental, a little too complex, a little too magical. I lean towards
R7RS and CHICKEN myself, which are on the opposite end in terms of Scheme
implementations. Guile's nice too.

~~~
TheMagicHorsey
I do agree, that it gets too big. I mentioned complexity for that reason.

Its also not very performant, BUT you can call C functions quite easily, and
you can embed Racket programs into your existing C/C++ programs.

~~~
qwertyuiop924
Yeah, but Chibi, CHICKEN, Gambit, and Guile are all excellent at FFI, and
fairly good at embedding (although for CHICKEN and Gambit, it depends on the
given value of embedding... That's more Chibi and Guile's forte, as it was for
SCM, SIOD, and TinyScheme before them.)

------
edem
Why use this over Clojure if I'm into Java?

~~~
pvinis
I see the answers below and I want to ask everyone. Is there any other lisp
besides Clojure right now, that is actively developed but not early stage, and
also not old? I want to use lisp and I don't care about the JVM. But whenever
I search for lisps, I find some for C, Go, Rust that are too young, or Common
Lisp which I read is too old and weird, and complicated. I really like Clojure
and that's what I use for now, but a lisp without the JVM mighty be cool.

~~~
qwertyuiop924
Clojure... well, I wouldn't go so far as to say it's "not a lisp" (some people
would), but it's quirky. It's like that weird guy who's just as competent as
the rest of us, but has an "interesting" perspective on how he tackles
problems. The example I got in another thread on this is:

    
    
      (list? '(1 2 3))
      ;;; => true
      (= '(1 2 3) (cons 1 '(2 3)))
      ;;; => true
      (list? (cons 1 '(2 3)))
      ;;; => false
    

That's actually psychotic: if your lists aren't lists, than don't call them
lists!

Anyways, Scheme is the part of the lisp family tree that actually evolves,
albeit slowly. The spec is minimal, so compatability between implementations
is low. I'd reccomend either Chicken or Guile scheme to most people, as both
have pretty good FFI, decent performance (Chicken's is better), and good
libraries (for a scheme).

Racket isn't a Scheme, although it started as one. The official implementation
of Arc runs on an old version of Racket, from when it was closer to Scheme (we
should probably port it to another scheme at some point...). It's not really
my thing, but you might like it, and it has some of the best library support
of any lisp outside Common Lisp.

OTOH, you may like Common Lisp. Bits of it are idiosyncratic, and it's huge
and inelegant, but it's a tremendously powerful language, and very well
supported and documented. There are actively developed implementations, and
the most popular is probably SBCL.

~~~
emidln

        (list? '(1 2 3))
        ;;; => true
    

'(1 2 3) is, in fact, a list of 3 elements

    
    
        (= '(1 2 3) (cons 1 '(2 3)))
        ;;; => true
    
      = is closer to equal? in scheme. The doc string for clojure.core/= explains this pretty well:
    
        Equality. Returns true if x equals y, false if not.    Same as
        Java x.equals(y) except it also works for nil, and compares
        numbers and collections in a type-independent manner.  Clojure's immutable data
        structures define equals() (and thus =) as a value, not an identity,
        comparison.
    

Finally,

    
    
        (list? (cons 1 '(2 3)))
        ;;; => false
    

`cons` is defined over a sequence in Clojure, not a list. The doc string
actually says this upfront "Returns a new seq ..." and the type of this
happens to be a `clojure.lang.Cons`. To get add a value to a list, you would
actually use `conj`, which conjoins a value onto a collection or sequence in a
way that is specific to that collection or sequence.

    
    
        (list? (conj '(2 3) 1))
        ;;; => true
    

If you are dead-set on using lists for some reason (you probably want a
different datatype in Clojure), you could always define:

    
    
        (defn cons?
          [x]
          (instance? clojure.lang.Cons x))
    
        (defn list-cons
          [v l]
          (cond
            (cons? l) (list-cons v (into '() (reverse l))) 
            (list? l) (conj l v)
            :else     (throw (AssertionError. "Assert failed: list-cons requires a PersistentList or a Cons."))))
        

If you really want a Lisp-style cons with pairs and such, you'll need to
define that yourself. It's not hard, or particularly useful, but if you really
feel you must...

~~~
lispm
Unfortunately they print as (1 2 3), even though they are different data
structures. A naive user would think that if (1 2 3) is a list, then anything
that prints like (1 2 3) is a list... printing it and rereading it -> I get a
new data structure type. Really?

Added with the random use of Lisp names to mean something different, while
claiming to be a Lisp, this is only creating confusion.

~~~
emidln
Cons prints the same as a list, which means when it is read, it _is_ a list.
'(1 2 3) is a PersistentList, not a Cons. In particular, this is what I
expect:

    
    
        (= foo (read-string (pr foo)))
    

As it turns out, in Clojure this holds (because = isn't identical?):

    
    
        (use 'clojure.test)
        (let [kons (cons 1 '(2 3))
              kons-str (pr-str kons)
              read-kons (read-string kons-str)]
          (is (instance? clojure.lang.Cons kons))
          (is (not (list? kons)))
          (is (string? kons-str))
          (is (= "(1 2 3)" kons-str))
          (is (list? read-kons))
          (is (not (instance? clojure.lang.Cons read-kons)))
          (is (= kons read-kons)))
    

Does this _really_ create confusion for more than the 30 seconds it takes to
read the doc string of clojure's cons? I don't know about you, but when I move
to a different language (even a different lisp), I don't assume things always
work exactly like they do in Common Lisp. When I came to clojure, I even took
a look at the old version of this page:
[https://clojure.org/reference/lisps](https://clojure.org/reference/lisps),
which details this and other differences from the Schemes I had mostly used in
the past.

~~~
qwertyuiop924
That may only create a few seconds of impedance, but it's still utterly
psychotic and insane. Once again: if cons isn't cons, than don't call it cons.
I don't assume that everything works the same way everwhere, but if you take
your primitive function names from another language, and have them behave
differently, people _will_ be confused.

I mean, sure, if the semantics of cons are a bit different, okay, but you
can't just take the name and put it on a function that doesn't work at all
like cons.

It also violates homoiconicity, and the fundamental guarantee of the reader:
what you read in is the same as what you wrote out.

~~~
emidln
> doesn't work at all like cons

clojure.lang.Cons follows what CL's cons does with exactly one deviation: cdr
must implement clojure.lang.ISeq. The practical effect of this is that you
don't get a Cons cell as a primitive building block, but you don't need that
because you have deftype (or one of the many higher level interfaces in
clojure, which tend to be faster anyway since deftype will end up using java
fields for storage, which the JVM understands very well). I don't have to
build up my own alist using a list of pairs containing keys and values because
I just use a map. Further, when I'm using deftype, if I implement the right
interfaces, the core clojure sequence functions like conj, first, rest, map,
filter, reduce, etc will all work on my custom type, without me inventing a
namespace worth of custom implementations for those.

> violates homoiconicity

Clojure code isn't written using Lists, Vectors, Strings, Maps, Keywords, and
Symbols? I guess I'll stop writing macros then. No clue how they ever managed
to work.

> fundamental guarantee of the reader

AFAICT, clojure's printer makes no such contractual guarantee here. FWIW,
neither does CL (witness the thousands of subtly (and not so subtly)
incompatible read tables floating around). In clojure, the printer, out of the
box, prints values in such a way that they can be read back in in a way that
is `clojure.core/=`. It's unreasonable for them to be
`clojure.core/identical?` (which is essentially asking if they are the same
memory as before (this isn't even something that Common Lisp or Scheme does,
mostly because it's pretty insane unless you statically map out all of your
memory)). I mention out of the box because you can change the printer and
supply additions to the object tag reader (or even to throw out clojure's
reader and use one of the reimplmentations as a library).

~~~
qwertyuiop924
>clojure.lang.Cons follows what CL's cons does with exactly one deviation: cdr
must implement clojure.lang.ISeq

Well then, it's not a cons, is it? It's actually a particularly weird
implementation of push, which stores the pushed item in another cell. If
you're not going to put cons in your language, fine, but be honest about it.

>Further, when I'm using deftype, if I implement the right interfaces, the
core clojure sequence functions like conj, first, rest, map, filter, reduce,
etc will all work on my custom type, without me inventing a namespace worth of
custom implementations for those

So you have high-level collection functions that act the same between
collections? Good for you guys. Lisp and scheme have had that for ages. But
don't call your high-level functions by the name the low-level functions are
expected to be called, and expose those low-level functions: sometimes a
function wants to know what sort of structure it's manipulating.

>Clojure code isn't written using Lists, Vectors, Strings, Maps, Keywords, and
Symbols? I guess I'll stop writing macros then. No clue how they ever managed
to work.

Okay, yeah, I miswrote that, it doesn't violate homoiconicity. But I disagree
vehemently about the reader. Assuming the readtable is in the same state,
anything you write out _can_ be read back in to give the same structure in
RAM: that's why you can use write to serialize state.

Also, by the above, clojure violates commutative equality, which is bad in any
language that claims to support FP: If a property is false on an entity, than
an entity that entity is equal to cannot have that property be true.
Otherwise, they're not equal.

------
Kabie
`de` and `prin`, wut?

~~~
eggy
'define' \- Scheme, Shen, others; 'defn' \- Clojure; 'fn'; 'lambda' \- are all
just syntax to get used to in any language you learn. The online
documentation, rosettacode.org examples, or the two reference books for
PicoLisp should help get you started.

~~~
fredmorcos
I think they were referring to the fact that 'de' isn't much of a shorthand
for 'def' and that 'prin' isn't much of a shorthand for 'print'.

~~~
eggy
I would say they are much more shorthanded than 'define' for define. Then
again, I program in J too, so I am used to one character or two character
tokens.

Wut? I understood as shorthand for 'What?' ;)

~~~
qwertyuiop924
Yeah, someone said that Scheme was like the Java of the Lisp world. It's not
_that_ verbose. But it can be fairly verbose at times.

~~~
eggy
I never heard that one. I mean you can just use shorter names. After all, you
define the functions, or at least most of them, and the built-in ones are not
unusually long. The Scheme programs are usually much shorter than most of
their counterparts on rosettacode.org. I program in J, and that is even
shorter! For me, the slight against Java is the length of the class names
themselves (e.g. TransactionAwarePersistenceManagerFactoryProxy), and all of
the curly braces mixed with all sorts of other line noise ;

~~~
qwertyuiop924
Some of the are pretty long, but the worst of them (call-with-current-
continuation most famously) usually have abbreviations (call/cc).

Java's evil isn't just it's long class names: It's also the language's general
verbosity: in some cases, I'd say it approaches COBOL levels of verbose. The
other evil is the import paths: Python got this one right. You don't want
org.companyname.lang.java.org.net.project.net.classes.AbstractClassFactoryFactory.

That import path isn't as much of an exageration as you'd think: if Java had
been invented a little earlier, it would have been banned from most computers
as a criminal waste of inodes.

