5 comments

[ 2.7 ms ] story [ 17.9 ms ] thread
Axel is a programming language project I've been working on for a couple years to scratch a personal itch: namely, to help alleviate the pain of Template Haskell by integrating a Lisp-esque macro system into Haskell. Axel's syntax is Lisp-like but the semantics are those of Haskell, so (IMHO) it's a happy medium between the two.

It is still very work-in-progress (as the GitHub issues make obvious), but I can no longer resist the temptation to share :-)

Any feedback/questions are appreciated – this is both my first non-trivial PL project _and_ Haskell project, so I'm sure there are many areas for improvement.

That is amazing, well done. I think it deserves more discussion so hopefully I can start some.

I've dabbled in Haskell and Lisp but really just touched the surface.

My question is how hard was it to do macros with Haskell where I assume it needs to produce code that is strongly typed. If you write a macro that produces a typing error, does it just crash, or return a Err from a Either Program Err? But then you have something that could "crash", because what do you do with that Err. It would be probably impossible to type check a macro in general at compile time (as in the first compilation, not compilations done at runtime), since it has unlimited potential inputs.

Other question is how doe this compare to Racket? Did you use Racket to build this?

Thank you (sorry for the late reply)!

The macro system is not strongly-typed in the sense that Template Haskell is: you can totally use a macro to create invalid Axel code. _However_, the resulting transpiled Haskell code will then fail to compile, so mistakes are still caught at compile-time. (There's no runtime code generation (at least not yet), since all macro expansion happens at compile-time.) I hope this makes sense; I'm not 100% sure what the right terminology is to be honest.

You called it, I'm basically just using `Either` for error-handling (well, the equivalent version in the Polysemy library). It's basically like `EitherT`, except IMHO more ergonomic. However, since I'm using the transformer version, I'm just exiting the entire program on an error and printing an error message.

Regarding Racket, I hope you don't mind if I quote myself (from https://github.com/axellang/axel/wiki/Why-Axel%3F):

> Axel was originally inspired by the excellent Hackett project, which adds Haskell's semantics to Racket's syntax and ecosystem. Axel is the "opposite" of Hackett, so to speak, in that it adds Lisp's syntax to Haskell's semantics and ecosystem. Axel tries to make the migration from Haskell as seamless as possible: You can gradually migrate a Haskell project to Axel if that works best for your project; Axel can (soon) auto-convert a Haskell project or file to the corresponding Axel syntax; etc. If you really love Racket (its libraries, hygenic macro system, etc.), however, Hackett's an excellent choice.

Didn't we have that before already? Liskell I think was the name. Decades ago.
Good catch, you are correct. I tried to justify creating something new on https://github.com/axellang/axel/wiki/Why-Axel%3F under "... Another Lisp?" (apologies for the "marketing" feel, and for quoting myself :-P ):

> Axel aims to be a spiritual successor to Liskell. At the time of writing, Liskell's last commit was in 2009, so Axel tries to take over where Liskell left off. Axel hopes to provide a production-ready Lisp on top of the Haskell ecosystem, while emphasizing developer experience along the way.

If nothing else, I'm also hoping to just give the idea of a Lisp-like Haskell another chance, 'cause I think it's cool :-)