eevo script
Everything should be as simple as possible, but not simpler
- Albert Einstein
eevo is a lightweight yet expressive high-level scripting language for data-driven programming. Centered around functional records, many ideas are unified into a single model, enabling concise, modern, and hackable code.
- Simple: Built on a minimal set of composable concepts.
- Small: Extremely lightweight with less than 100KB binary and 2k lines of C99
- Sweet: Syntactic sugar for easy and readable syntax, with invisible s-expressions underneath
- Symmetric: unification of many ideas with uniform syntax. Same principals and syntax are applied universally.
- Symbolic: Symbols are first class citizens, and code is data
- Separable: Modular design allows you to use only what you need, or modify each component to suit your needs
- Script-able: Ideal for interactive shells, quick scripts, or scientific calculator
def fib(n)
"Fibonacci number of n"
if n < 2
n
fib(n - 1) + fib(n - 2)
fib 25 ; = 46368
A lightweight modular core allows you to choose how much of the language you need. This comes in a few layers:
- Read/Print: Parse expressions and output data structures unevaluated (eg data or config files)
- Evaluate: Execute the code; transform and simplify expressions
- Core: Essential functions and syntax (eg flow control, list manipulation, basic math)
- Standard Library: Additional functions needed for common operations (eg IO, math, doc)
- Contrib: Community-driven libraries and scripts, officially sponsored
While eevo is a general purpose programming language, that does not mean it is the best tool for every problem. Like all languages, eevo has many design decisions which have different trade-offs in different situations. To solve problems that are ill-suited to eevo’s design (such as requiring circular references or precise mutations) other languages can be called upon through C-bindings (and soon WASM).
This interoperability also makes it easy to offload computationally heavy code to another language or gradually replace existing code with concise scripts. This enables a dual approach which make eevo a great glue language to bridge languages in two directions:
- Extend eevo by embedding
another language as a library
- Out source computationally expensive code to low level libraries.
- Embed eevo in another program to
extend it
- Slowly replace existing low level code with a high-level hackable scripting.
Both methods can be done at the same time with different languages, allowing eevo to glue different libraries, ecosystems, and tools together.
Warning
eevo is still in active development and not yet stable. Until the
v1.0
release expect breaking non-backwards compatible
changes.
Features
High-level
- Developer can focus on important logic, not boiler-plate
- Let eevo worry about implementation details, optimizations, data representation
Functional programming
- All you need is data, and functions to transform that data
Interactive
- Read, Evaluate, Print, Loop (REPL)
First Class Types
- Numbers: integers
Int
, decimalsDec
, ratiosRatio
- Booleans:
True
,Nil
- Text: strings
Str
, symbols (identifiers/variables)Sym
- Lists, pairs
Pair
- Records:
Rec
- Environments (namespaces/modules/capabilities)
- Functions: with closures
Func
,Func
for anonymous functionsPrim
for external functions written in another language
- Macros: functions which transform code
Macro
,Form
- Types
- Void
- Errors
Records as universal type
- Arrays, dictionaries, functions, environments, sets, types, strings are all modeled as records
- Functions are records with infinitey many
Metaprogramming
- Homoiconic syntax allows for powerful and simple macro system
- Abstract away boiler-plate, cost free
- Customize syntax to extend language with new features
Quoted expressions
- Code can be quoted to avoid (or delay) its evaluation
- Allows code to be manipulated like data
- Quasiquote enables some of the code to be unquoted and evaluated
Literate Programming
- Write documentation directly inside an eevo script, which is converted to Markdown
Tail call optimization
- Recursive loops become computationally equivalent to imperative loops
Dyslexic friendly
- Primarily designed by someone with dyslexia. The language, standard library, and documentation are designed to be as easy as possible to read.
See the language manual for complete set of features.
Anti-Features
Just like jazz, what is missing is often more important:
No mutability
- Mutations make programs difficult to predict and harder to read,
increasing the mental load of every line of code
- Given the same code and data you always get the same result
- Prevents the mistakes that come from half constructed values
- Change should be modeled one way: function calls
- Mutations should be an optimization performed by the compiler
- Allows for easy optimizations such as automatic parallelization
- Removes circular references, making automatic reference counting easy
No dependencies (eg LLVM)
- Dependencies are just someone else’s code, which silently increase the surface error of potential bugs
- Only relies on a C compiler and libc
No statements
- Everything is an expression (
5
,"hello"
,def
,if
, etc)
No keywords
- All symbols are equal and can be redefined at will
No reader macros
- Limit amount of the language that can be modified
- Should be easy to read anyone’s scripts
No exceptions
- Errors are just regular values which have to be explicitly handled
No multiple return values
- Just return a list, and require callee to explicitly expand into multiple values
No explicit return
- Last item of procedure is always returned
- Use Void to explicitly avoid returning last value
No arrays, linked lists, or tuples
- Just pairs (2-tuples) and records
No function currying
- Functions only take one argument, but it is often a list of arguments
- You are welcome to write functions in the curry style, but the standard library is not written that way
No garbage collector
- Memory is managed through reference counting
No build systems
- Simply run the primary
.evo
file (by convention the same name as the project) and let it handle including and running all other files as needed
No mandatory editor tools
- Syntax should be easy to modify without specialized tools
Coming Soon…
Automatic reference counting memory management
- Memory is initially allocated on the stack with a region allocator
- Values which escape their scope are evicted to the heap and reference counted
Strong static typing with type inference
- First class
- Algebraic data types (sum, product, exponential)
- Physical units
- Uncertainty
- Polymorphism
- Row (record) polymorphism
- Refinement types
- Codata
- [Type holes][type-holes]
Batteries included standard library
- While still being minimal and orthogonal
Powerful string interpolation
- templater (eg mustache, handlebars)
- unformat
- regex alternative
WebAssembly compiler
- Web interface, environment, and REPL
Interoperability with any programming language with C bindings
- WASM, C, Lisp, Python, Lua, Rust, Go, shell, etc
First class algebraic pattern matching
Improved error messages
Environmental image
- Restore the environment exactly how you left it.
Hygienic macros
- Avoid variable capture with macros
- Simple without need for
syntax-rules
orgensym
, similar to s7
Multithreading
Managed effects
- Control effects through capabilities via first class environments
Full Unicode support
- Encoded in UTF-8
Optimizations
- Total pre-computation
- Anything that can be computed at compile time will be
- Constant folding and propagation
- Opportunistic in place mutation
- Memorization (cache)
- Strings and symbols are already interned
- Auto parallelism
- GPU acceleration