Picolisp
picolisp.com
picolisp.com
Work has been done to run it on bare metal too - a sort of LISP Machine in PicoLisp!
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).
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 ;)
...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.
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.
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.
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.
I mainly use Lisps for livecoding. I am currently trying to learn Extempore for livecoding. It has two languages: xtlang, a Lisp language that is strongly typed and compiled for close to C speed via LLVM, and a scheme for doing more high-level scripting stuff in the Extempore environment [1]. There are binaries available for all platforms. I run it in Spacemacs on Windows 8.1. It's very snappy, and powerful, for coding music/sound at the signal or note level, and it has OpenGL and Nanovg for graphics. Watch Andrew Sorensen rock it on YouTube or Vimeo - just search for Extempore and/or Andrew Sorensen. I hope there will be a way to distribute things created with it someday. Then it would be a kick ass game dev platform.
I tried Racket and SBCL briefly specifically for games. Both are very capable. I will probably go back to SBCL, since it worked well with SDL2, OpenGL and was fast on both my Windows and Linux boxes. CEPL is great for working with OpenGL in Lisp [2].
I would love to use PicoLisp. I almost did use it for a game jam, but you would need to create the game framework from the pieces it has, and again, the Posix / Windows issue. I'm really hoping for the Midipix solution. You can learn PicoLisp fast in a week or so by following along with the two great books - PicoLisp Examples, and PicoLisp Works. The PDFs are freely available on Scribd and the source code is available online [3][4].
Even Erlang is available as a Lisp - LFE, or Lisp Flavored Erlang, created by one of the original designers of Erlang, Robert Virding. Would be great for a game server with many connections. Elixir is becoming very popular but LFE has true macros, and why not, it's a Lisp! [5]
[1] http://extempore.moso.com.au/
[2] https://github.com/cbaggers/cepl
[3] https://github.com/tj64/picolisp-by-example
[4] https://github.com/tj64/picolisp-works
[5] http://lfe.io/
Guile's Sly is also quite good for 2d work.
Finally, I think both have bindings to raw OpenGL/SDL, if you want them.
Like PicoLisp Chicken is really Posix-dependent. Sure you can run it, and run the IUP examples on Windows, but as soon as you try to use the eggs you mention, the dependencies on the Posix stuff puts it on the backburner for me.
Right now, my game dev tools are Raylib(C)[1], Godot game engine[2], Processing(Java)[3], and CL(SBCL, SDL). All allow me to distribute games to Windows and Linux minimum. A few can do almost all platforms - Android, iOS(if you have a Mac!).
I still think Racket is an excellent playground to test concepts, and short of distributing games, valid for most anything. Pict3D package is very interesting.
Raylib is amazing. I have had a C renaissance because of it. Very clean and organized.
I am currently trying to embed s7(Scheme)[4] into a Raylib project in hopes of having my cake and eat it too!
Another playground for livecoding, but no way to share standalone 'apps' is Extempore, as I have mentioned previously.
[4] http://carloscarrasco.com/a-love-letter-to-s7-scheme.html & https://ccrma.stanford.edu/software/snd/snd/s7.html
You might also wish to try Chibi for embedding, but both it and s7 are pretty good. I am also unsure as to how POSIX dependant chibi is.
brew reinstall --build-from-source picolisp
and it worked.
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?
> [...] as a special case - if the CAR of the list is a number, the whole list is returned as it is [...] This is not really a function call but just a convenience to avoid having to quote simple data lists.
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.
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.
(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.
(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...Added with the random use of Lisp names to mean something different, while claiming to be a Lisp, this is only creating confusion.
(= 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, which details this and other differences from the Schemes I had mostly used in the past.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.
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).
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.
Even though both print as (...)?
Okay...
Also, lisp pairs are very useful.
user=> (type (cons 1 '(2 3)))
#<Class@bc57b40 clojure.lang.Cons>
user=> (type (conj '(2 3) 1))
#<Class@6137cf6e clojure.lang.PersistentList>
user=> (seq? (cons 1 '(2 3)))
true
user=> (seq? (conj '(2 3) 1))
trueBut seriously, Clojure is designed from scratch to work well with the JVM, so if the JVM's where you live then Clojure is the obvious choice.
Wut? I understood as shorthand for 'What?' ;)
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.