Hacker News new | past | comments | ask | show | jobs | submit login
Owl Lisp – A purely functional Scheme that compiles to C (github.com/aoh)
140 points by rcarmo on Sept 10, 2016 | hide | past | favorite | 43 comments



Owl's pretty nice, but I wish it was documented better: I can't actually get into it, because I have no idea what is valid Owl.

Also, I like how it doesn't call itself Scheme, because it's not Scheme.

This is a problem that annoys me: people seem to think that if you're a lisp-1, and you follow a few naming conventions, you can call yourself scheme. That's like calling yourself Common Lisp because you're a lisp-2 with setf.

Scheme is a family of languages, true, but it does have a formal spec, and if you do not follow it (or at least approximate it), than you are not scheme. Scheme inspired, or scheme derived, maybe, (Racket got this one right, and changed its name once it started going too far afield, thus saving us from having to explain to 1000 confused newbies that PLT Scheme isn't Scheme, and now must only deal with people who tell newbies that Racket is Scheme) but if you don't meet IEEE or RnRS, or at least Scheme as described in AIM-349 (the original Scheme: a radically different language from Scheme today), than you're not Scheme, and if you call yourself that, than you'll confuse people.

/rant


The title is "a purely functional Scheme..."


No, no, I think Owl did well, because it didn't say that it's scheme, at least up front. It's honestly more akin to DSSSL than anything else. Saying that it's "functional scheme" is far less likely to cause confusion than some of the other things people have done.

EDIT: No, it's not like DSSSL, and it's less cool than I thought it was. It's still cool, though.


I really like the growing interest in making lisps that compile to C, and one that is purely function is even better. I'd be curious how the GC in this compares to the fascinating work in Chicken for novel GC in C environments.


If you find Lisp to C compilers interesting, then Common Lisp has a bunch for you. The first CL to C compiler was KCL (Kyoto Common Lisp from Japan in the mid 80s). It is the parent for several other compilers.

Gnu Common Lisp, Embeddable Common Lisp, mkcl, mocl. There are also attempts at C++ as a target language. See CLASP.

https://www.gnu.org/software/gcl/

https://common-lisp.net/project/ecl/

https://common-lisp.net/project/mkcl/

https://wukix.com/mocl

https://github.com/drmeister/clasp


Cool, but then you have to actually deal with Common Lisp, which is not the kind of lisp that interests me. The more functional-oriented lisps like this Owl, and Clojure, are quite different in many ways from CL.


I agree that Chicken is based on a brilliant idea that turned out to work really well in practice. It's a very practical language / implementation.


It's my favorite Scheme. It's minimalist, but practical, and usable for Real Work. It's everything I like about Racket, without all thinks I don't like about Racket (Racket's a fine language, it's just not my thing).


It is not practical enough for me to have a language which does not support native threads.


Only Guile does that, AFAIK. And Chicken's threads are perfectly usable in most cases. And you can always fork(2), if you really want to.


And as I read it sometime ago while searching for Scheme implementations with native threads, Cheney on the MTA is inherently single threaded.


Not necessarily, it can be extended to support multithreading:

https://github.com/justinethier/cyclone


Cyclone is a new Scheme with native threads that uses cheney.


There are ways to use native threads with Chicken; it's a bit hairy, though.

Chicken 5, the upcoming partial rewrite, is worth keeping an eye on.


I've got an upcoming talk at EuroClojure on the subject:

http://euroclojure.org/speakers#mreitzenstein

Taking advantage of immutability and using clojure.spec generators at the top level, it specializes/simplifies the code using really simple transformations.

Demo of the specialization here:

http://reitzenwebserv.s3.amazonaws.com/opt/index.html



The perf is generally comparable (each has optimizations the other does not, although gambit is a bit faster in the general case), but Chicken has really fast call/cc. Also, Gambit has a very small library collection, especially compared to Chicken's, which is among the best of all the schemes, Library-wise. Neither supports native threading, and Chicken isn't fully re-entrant, which can lead to some problems integrating some libraries. Both have excellent FFI, but Chicken's is a bit better, IMHO.


What's so novel about Chicken's GC? Cheney on the MTA is quite clearly novel (Chicken compiles to CPS and essentially GCs its stack frames IIRC, making call/cc as fast as any other procedure call), but the algorithm itself is quite ordinary, IIRC.


Very cool! By purely functional I'm guessing they mean immutable by default? Aside from Clojure, what other Scheme/Lisp implementations are immutable by default? I know Lisp-flavoured Erlang is due to being on the BEAM but I'm curious what else is out there.


I'm looking through the tests, and there's side effects everywhere. I'm confused as to what the author implies by "purely functional", so it would be nice to have some additional information.


There are definitely I/O side effects, but it looks like functions for mutating data structures (like set-cdr!) are intentionally unimplemented: https://github.com/aoh/owl-lisp/blob/master/scheme/base.scm#...

That must be what they mean by "purely functional".


....soo, it's racket, but without all the shiny libraries and mcons.

It sounded like it was going to be general-purpose DSSSL. That would have been so much more cool.


Scheme is immutable to at least the same degree as Clojure (which is to say, there are mutable values, but their use is discouraged by convention).


Purely functional doesn't mean immutable by default - it means immutable, period.

A function called with the same arguments will always have the same result.


If I understand what you mean by "immutable by default", then it's all Scheme implementations, and probably all Lisp as well.


Common Lisp variables are not even a little bit immutable by default. setf is the opposite of immutable values, you can mutate any place in a way that's visible everywhere regardless of any sort of scoping.

Immutable by default might be what you'd get if CL only had let to introduce/"change" variables.


Scheme is always mutable, all the time, it just has separate functions for defining and mutating a variable.


What about set-car! set-cdr! vector-set! string-set!


If you can't easily avoid those, you're not going to be capable of doing much else anyway.


I was responding to "If I understand what you mean by "immutable by default", then it's all Scheme implementations"; not whether one should or should not use mutating operations!


So what does "immutable by default" mean??? Is there even an agreed upon definition? Because you certainly didn't explain / explain clearly if that's what you were attempting to do... Clojure has mutable vars and set!, so it seems Scheme is no worse and fits that guy's definition of IbD.


Consider:

  (define x (vector 1 2 3 4))
  (define y x)
  (vector-set! x 0 100)
Should y[0] be 100 or 1?


That's not really relevant. According to the guy's own definition, Scheme is as immutable as Clojure, which is what he was specifically asking. They both have something like set!. If you want to wank off about Scheme not being 100% immutable, go right ahead, but it's clearly not what was being discussed.


They are discouraged by convention.


C++ has many pure functional features that C lacks. For example immutable methods with const and Lambdas. Wouldn't these features make it easier target to C++ rather than C? Do these functional features only make it easier for a human to write functional code or is there some other reason these Lisps all use C?


If you're writing a compiler, you're going to want to explicitly manage closures and function pointers anyway.


If you're passing around your environments in the C code (which you should be doing anyways), than there is no reason it would be easier to target C++.


Lambdas are actually just a nice way to write functions/function objects without polluting the scope.

I guess a compiler have no such problems.

Immutable methods are the same thing as a safety check for humans. As you want to check for these things anyway (since you probably don't want errors to come from the c++ compiler), they don't add value.

(AFAIK, they may trigger optimizations, but so does passing const parameters to a free function, which is the C equivalent)


Since you're compiling and not interpreting, you can do all the checks that a variable doesn't get mutated at compile-time. There's no need to defer these checks into the C code.


It's not purely functional if it supports side effects all willy-nilly. Scheme sans mutation (which is not the same as Racket, since Racket's stdlib still supports mutation) is no more purely functional than modern C++ sans mutation.

With that said, purely functional programming is arguably just a hassle; I tend to think that "functional-first," as I call it, programming, a la Clojure, is a good balance between practical and pure. In this way, side effects are adhoc, but all definitions are immutable by default.


aoh also wrote the very awesome Radamsa fuzzing engine in it - https://github.com/aoh/radamsa


Yeah, unfortunately my only exposure to owl lisp is wishing that Radamsa wasnt written in it so I could understand/modify radamsa better.

Radamsa is seriously awesome.


...and that's 100% my experience with it too :-/

Awesome fuzzing engine but modifying it is not for the faint of heart.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: