small,
`___` embeddable
(o,O) and
\) ) purely
---"-"--- functional!
O t u s L i s p
Based on Aki Helin's Owl-Lisp
Otus Lisp (Ol in short) is a purely functional, multi-platform Lisp dialect with built-in FFI, regular expressions and infix math notation support.
Ol implements an extended subset of the R7RS Scheme (PDF), including but not limited to some SRFIs. It is tiny (~ 64KB), embeddable, and cross-platform; provides a portable, high-level interface to call code written in another language (c, python, lua, etc). You can call native OS functions directly from your Ol program.
You can use Ol on Linux, Windows, macOS, Android, Chromebook*, (Open/Free/Net) BSD, Solaris and other operating systems based on various hardware architectures (x86, arm, ppc, mips, etc.), and directly in the web browsers (in WebAssembly form).
the-man-with-a-golden-mind (ideas, usage, lot of tests), nullscm (usage, tests), Odysseus (tests, ideas, math corrections), mt (tests, ideas).
The following breaking changes have been added to the master branch:
- âť—
values
with an empty argument list now returns #false instead of the string "no vals" - âť—
sqlite:value
no longer returns the result of sqlite3_changes() but simply #false if nothing was returned, use the "RETURNING" statement with INSERT and UPDATE if you want to return something. - âť— Welcome invitation changed
- âť—
procedure?
made r7rs compatible (will now return #false for ff's) - âť— arity errors changed (made more clear and descriptive)
-
Ubuntu (and it's descendants such as Mint, Pop!_OS, Xubuntu, etc.) users may use the official project ppa.
$ sudo add-apt-repository ppa:yuriy-chumak/ol $ sudo apt update $ sudo apt install ol
-
CentOS, Debian, openSUSE, RHEL, SL, SLE, Ubuntu, Univention precompiled packages: OpenSUSE Build Service.
Some additional libraries can be installed using 'kiss' package manager. Instructions available at ol-packages repository.
-
Q. Some folders are empty (i.e. "libraries/OpenGL"), is it ok?
A. Yes, it's ok. Some parts of Ol project are separated into their own independent repositories.
Usegit clone --recursive
to get a full project. Orgit submodule init; git submodule update
to update existing one. -
Q. Why no arrow keys processing and a history in Ol command line?
A. For the gods of simplicity. I recommend to use an rlwrap tool
(run asrlwrap ol
in terminal, or add analias ol="rlwrap /usr/bin/env ol"
line to your ~/.bashrc and run as justol
). -
Q. .. fatal error: stdlib.h: No such file or directory.
Q. .. fatal error: bits/libc-header-start.h: No such file or directory.
A. Install gccmultilib
, i.e.apt install gcc-multilib
for debian-based,apk add musl-dev
for alpine-based,- etc.
-
Q. You reference to licenses MIT and LGPL. Can I freely choose between these two licenses?
A. Yes, you are free to choose an MIT or LGPL license. -
Q. I want to run Ol in a venv (Virtual ENVironment). Can I?
A. Yes. Use--home=yours-venv-folder
command line option (more about venv).
Additionally, you can embed such a venv into the Ol executable itself (the portable form). -
Q. Anything else interesting?
A. Yes, Ol provides simplest HTTP web-server for sharing a local folder over an inter/intra-net.
Just typeecho ,load http/server| ol
in command line (or,l http/server
inside Ol session),
changeol
tool - --port 8080
to use the custom port. -
Q. Why do you call the characters not "characters" but "runes"?
A. Because they are runes - universal naming for letters for a wide set of alphabets. -
Q. Do you have something like "sleep mode"?
A. You can store the current REPL session with,save "filename"
and exit Ol. Then just runol filename
later to continue the saved session. -
Q. I'm lost in prefix math notation, can you help me?
A. Ol has a special math library that provides infix math notation. Use the(math infix-notation)
library.> (import (math infix-notation)) > (print (infix-notation 1 + 2 * 3 - sqrt(4) )) 5 ; '\\' is a short for infix-notation > (print (\\ 1 + 2 * 3 - sqrt(4) )) 5 ; you can review result of transformations with ",expand" > ,expand (\\ 1 + 2 * 3 - sqrt(4) ) (- (+ 1 (* 2 3)) (sqrt 4))
Join the online gitter.im chat. Alternatively the Libera.Chat #otus-lisp (alternate lightweight web-client) channel is available (the previous Freenode channel is closed).
The Issues github page waiting for your bug reports and issues.
- Packaging
- Build/Run/Install
- Running
- Language Reference
- FFI
- Hacking
- Lisp sources in binary form
- Files, Docs
- License
- GCC 3.2+ / CLANG 3.5+
- GNU MAKE
$ make
Advanced build instructions: doc/BUILD.md
$ ./ol
Welcome to Otus Lisp 2.6
type ',help' to help, ',quit' to end session.
>
The Ol binary includes a rich set of features (lists, vectors and bytevectors, ansi and unicode strings, infinite precision math, associative arrays aka "ff"s, i/o streams, lazy evaluations, regular expressions, continuations, exceptions, lexer parsers, async functions and actors, etc.) and can be used as a completely standalone.
$ sudo make install
Note: by default we use /usr/bin/ol for Ol binary, and /usr/lib/ol/ folder for Ol libraries.
$ sudo make uninstall
The Otus Lisp language is based on Scheme R7RS (PDF) with minor changes and useful extensions.
You can find working Ol examples at:
- Standard procedures list (constantly improving),
- RosettaCode Ol page,
- Tests and Examples repository folders,
- Android example code available at android folder.
Additionally,
-
"LogicWire" and "Digital rain" examples demonstrates native libraries direct usage (the OpenGL):
-
"Pacman" sample demonstrates embedding Ol scripts in native "C" code - https://github.com/yuriy-chumak/ol/tree/master/examples/pacman
-
"Newton dynamics" sample demonstrates extended native libraries usage (the newton-dynamics, physical simulation engine) with callbacks (C to Lisp automatic translation) - https://github.com/yuriy-chumak/ol/tree/master/examples/Newton. You should have compiled newton-dynamics.so core library.
The most important differences are:
- Ol is definitely case sensitive.
- Numbers WITHOUT PRECISION considered to be exact in Ol, but inexact in Scheme.
integer?
for inexact numbers always returns #false in Ol.- note: Use
inexact
function to convert number into inexact form, or prefix number with#i
directly (like#i0.123
for inexact 0.123).
- No
set!
in Ol (Ol is purely functional!),- note: Use
define
,define-values
,let
,let*
,letrec
, andletrec*
instead. - note: Limited support of
set-car!
,set-cdr!
, andset-ref!
functions are provided, but is not recommended to be used. - note: Inexact numbers can be changed with
vm:set!
, but is not recommended to be used. - note: Dynamic variables are available via
(scheme dynamic-bindings)
library.
- note: Use
- CHARACTERS in Ol are small numbers (aka 'enums'), but special character type in Scheme.
- note: Ol supports the full Unicode 15.0.0 (2022 Sep 13) character set.
- note: To write a character use
write-char
, otherwise you'll write a number.
- NEGATIVE indices in
substring
are valid in Ol (means "from the end of string", -1 means a last rune). - NEGATIVE vector indices are valid in Ol (means "from the end of vector", -1 means a last element).
- Ol has extended form of
case
(with vectors support), - Ol has extended form of
if
(withthen
andelse
keywords), - Ol has builtin dictionary numeric and symbolic keys (the reference page),
- Ol has builtin regular expressions (the reference page),
- Ol has an awfully powerful macro system in addition to Scheme's hygienic one (a brief notes and examples).
apply
arguments count is limited to 249 in Ol (use afold
otherwise).
The nearly full differences list can be found in doc/R7RS-DIFFERENCES.md.
- srfi-0 -
cond-expand
, builtin - srfi-16 -
case-lambda
, builtin - srfi-71 -
(let* ((a b (values..
, builtin - srfi-87 -
<=
incase
, builtin
-
2.6 -> 2.7 (which is planned, but i'm not sure about)
- i'm thinking about changing
(wait ms)
to(wait s)
, it means the seconds usage instead of milliseconds.
- i'm thinking about changing
-
2.5 -> 2.6
- feature
ol-2.5
changed tool-2.6
. - removed deprecated libraries
(scheme srfi-Nnn)
, use(srfi Nnn)
instead, - i/o scheduler enabled by default for reads,
write
function made r7rs-compliant,(owl format)
moved to(otus format)
.
- feature
-
2.4 -> 2.5
- feature
ol-2.4
changed tool-2.5
. (system args port...)
changed to(execvp args port...)
. New(system command)
introduced.(OpenGL version-X.Y)
libraries changed to(OpenGL X.Y)
.fft-size-t
changed tofft-size_t
.HAS_...
build variables changed to convenientHAVE_...
.
- feature
-
2.3 -> 2.4
(ilist ...)
is deprecated. Use(cons* ...)
instead.(interact ...)
from (owlinteropasync) is deprecated. Use(await (mail ...))
instead.(fork ...)
,(fork-named ...)
,(fork-server ...)
is deprecated. Use(async ...)
,(async 'name ...)
,(actor ...)
instead.
Using external "asin" function instead of built-in one:
; import ffi library
> (import (otus ffi))
; load binary shared module (so or dll)
> (define LIBM (load-dynamic-library "libm.so.6"))
; declare external function prototype
> (define asin (LIBM fft-double "asin" fft-double))
; use the external function
> (print (asin 0.5))
0.523598775
Windows UI example:
> (import (otus ffi))
> (define USER32 (load-dynamic-library "user32"))
> (define MessageBox (USER32 fft-int "MessageBoxA" type-vptr type-string type-string fft-int))
; use the external function
> (MessageBox #f "hello world" "message box" 1)
1 ; 2 if you clicked "Cancel"
Ol contains built-in tool for inspecting the Otus Lisp language.
You can use the REPL ,expand
command to expand high-level Ol instructions into low-level (core) Otus Lisp.
> ,expand (assert (+ 1 2) = 3)
'(ifeq (equal? ((lambda (g1) g1) (+ 1 2)) 3) #true #true (runtime-error "assertion error:" (cons (quote (+ 1 2)) (cons "must be" (cons (quote 3) '())))))
You can use the REPL ,disassembly
(or ,dis
, or ,d
) command to disassemble Otus Lisp functions to the Ol virtual machine instructions.
> ,dis (lambda () 1)
type: bytecode
code: (11 1 0 5 14 1 4 24 4 17)
disassembly '(length command . args):
(4 JAF 1 0 5)
(3 LD 1 4)
(2 RET 4)
(1 ARITY-ERROR)
> ,dis (lambda (x y) (+ x y))
type: procedure
code: #((11 3 0 7 1 1 2 6 2 6 3 17) #<+>)
disassembly '(length command . args):
(4 JAF 3 0 7)
(4 REFI 1 2 6)
(3 GOTO 6 3)
(1 ARITY-ERROR)
You can use basic Ol functionality without any installation - just copy the ol
(ol.exe
for Windows) binary to any user-accessible path.
Basic functionality includes a rich set of features: lists, vectors and bytevectors, numbers math with unlimited accuracy, strings, associative arrays (named ff
), i/o streams and files, lazy calculations, regular expressions, asyncs and actors, etc.
Advanced functionality (i.e. OpenGL support) requires a complete installation of the Ol package:
- You can use precompiled binaries and/or installation packages that can be found at the Releases announcement page.
- or You can manually copy required libraries to your OL_HOME or current directory,
Ol command line is:
ol [options] [filename] [arguments]
- if no filename given ol will use stdin as source
- if you want to use stdin as source but must provide an arguments, use "-" instead
- i.e.
echo '(print *vm-args*)' | ol - arg1 arg2
- i.e.
- if you want to break vm-options scanning and provide filename like option (i.e. '--version' as a real file name), use "--" for 'end-of-option' flag and then a filename
- i.e.
echo '(print *vm-args*)' > --version; ol -- --version arg1 arg2 arg3
- i.e.
Olvm command line options available:
-v
: print olvm version then exit--version
: print olvm version and licensing information then exit
Ol command line options available:
-v
: print ol version then exit--version
: print ol version and licensing information then exit--version=...
: overwrite ol version string--home=...
: overwrite path where to search for the ol libraries--sandbox
: enable execution in the sandbox (if OS supports)--sandbox=Nnn
: execution in the sandbox with "Nnn" Megs of memory preallocated--interactive
: force REPL interactive mode--non-interactive
: disable REPL interactive mode--embed
: run special reduced REPL for embed usage--
: end-of-options sign
Ol can be executed interactively or in the unattended mode.
$ ol
Welcome to Otus Lisp 2.2,
type ',help' to help, ',quit' to end session.
; now you in REPL and can play with in
> (+ 1 2 3)
6
; or let's make some factorial calculations?
> (let factorial ((n 17))
(if (= n 0)
1
(* n (factorial (- n 1)))))
355687428096000
; this ends interactive session
> ,quit
bye bye :/
GNU/Linux, Unixes, *BSDs, macOS, ...
$ ol scriptname.ol # text script
$ ol scriptname.bl # binary (compiled) script
$ echo '(print (+ 1 2 3))' | ol
Windows:
> ol scriptname.ol
> ol scriptname.bl
> echo (print (+ 1 2 3)) | ol
OL can execute precompiled scripts. While text lisp programs require REPL (400KB), libraries, and time to compile, the binary code needs only olvm (90K with FFI, 60K without FFI) and is ready to run the code immediately.
You can compile your script using next code as a template:
template.scm
:
; put anything you want to compile in a lambda
(define (main args)
(print "arguments: " args)
(define out
(let faktr ((x (if (null? args)
13
(string->number (first args)))))
(if (= x 1)
1
(* x (faktr (- x 1))))))
(print "factorial: " out)
; return execution result
; (let it be number of digits in the out)
(ilog 10 out))
; compile and save this lambda into binary file
(fasl-save main "out.bl")
Let's compile and check the output:
$ ol template.scm
$ ls -l out.bl
-rw------- 1 user user 55549 Jul 21 23:13 out.bl
$ xxd ./out.bl
00000000: 0203 012b 0203 012d 0203 013d 0203 012a ...+...-...=...*
00000010: 0203 013c 0203 023c 3c02 0302 3e3e 0203 ...<...<<...>>..
00000020: 0474 7970 6502 0303 6164 6401 0401 0901 .type...add.....
00000030: 0401 0901 0401 0801 0401 0a01 0401 0901 ................
..........
0000d8c0: 0d03 0206 0111 0111 0501 c50e 0c08 0202 ................
0000d8d0: 1022 0b02 001d 0101 0205 0312 0401 0304 ."..............
0000d8e0: 0306 0101 0407 0505 0804 0505 0603 0704 ................
0000d8f0: 0208 0311 0111 0401 9a01 0210 00 .............
Now you can use this binary code anywhere without changes, even under another OS and/or platform, even with embed olvm code.
# fastrun with ol virtual machine
$ olvm ./out.bl
arguments: ()
factorial: 6227020800
# try with arguments and print execution result
$ ol ./out.bl 42; echo returned: $?
arguments: (42)
factorial: 1405006117752879898543142606244511569936384000000000
returned: 52
# regular ol can do it too
$ ol ./out.bl 7; echo returned: $?
arguments: (7)
factorial: 5040
returned: 4
A virtual environment is an Ol environment such that the libraries and scripts installed into it are isolated from those installed in other virtual environments and your operating system.
Use --home=folder
or --home=folder1:folder2:...:folderN
Ol command line option, where ':' is a folder divider. Folder names '.' and '..' are allowed.
These folders are linked to the Ol's *path*
global symbol and can be used and changed at runtime freely.
repl
- the compiled ol binary interpreter/compiler (olvm bytecode)src/olvm.c
- the ol virtual machine source code (C)includes/ol/ol.h
- the common ol header (C, not required, just for use as embed)includes/ol/vm.h
- the ol virtual machine header (C, not required, just for use as embed)extensions/ffi.c
- FFI implementation (C)lang/*.scm
- ol repl and compiler source codes (Lisp)libraries/**.scm
- various OL libraries (Lisp):libraries/scheme/core.scm
- r7rs core implementationlibraries/owl/*.scm
- legacy basic librarieslibraries/lib/*.scm
- external native library mappings- etc.
tests/**
- some basic automation tests (Lisp, C, Txt)tests/rosettacode/*.scm
- additional automation tests (Lisp), described at the Rosetta Code programming chrestomathy site.
Please refer to the embedding sample README.
Please refer to the project page or check the source codes - libraries/scheme/core.scm
Otus Lisp is available under 2 licenses: MIT License and GNU (L)GPLv3 License.
Copyright (c) 2011-2014 Aki Helin
Copyright (c) 2014-2025 Yuriy Chumak
Grew out of the Owl Lisp by Aki Helin: https://gitlab.com/owl-lisp/owl
Thanks to:
- the-man-with-a-golden-mind for the tests, ideas, and questions.
Resources: