The language is mostly inspired by the following 3 languages:
- Haskell (functional programming)
- Clojure (syntax, overall look & feel)
- ML (module system)
The compiler is even implemented in Clojure.
They are implemented as plain-old data-structures whose expressions get eval'ed by the compiler and integrated into the type-checker. That means it's actually possible to generate types via functions. However, most of the types in the prelude are generated via several macros that provide a more pleasant syntax to types.
The module system is heavily inspired by ML, and both signatures & structures are supported.
The main difference between Lux and ML is that ML separates signatures & structures from the rest of the language, whereas Lux implements them on-top of the base language.
While the means to do Java-interop will be provided (and there are already a few ways to do it that you can look-up inside lux.lux), Lux is commited to functional programming.
Unlike in most other lisps, Lux macros are monadic. The (Lux a) type is the one responsibly for the magic by threading Compiler instances through macros. Macros must have the Macro type and then be declared as macros.
However, just using the defmacro macro will take care of it for you. Alternatively, you can use the defsyntax macro, which also offers monadic parsing of AST tokens for convenience.
(case (: (List Int) (list 1 2 3)) (#Cons [x (#Cons [y (#Cons [z #Nil])])]) (#Some ($ int:* x y z)) _ #None) (case (: (List Int) (list 1 2 3)) (\ (list x y z)) (#Some ($ int:* x y z)) _ #None)