Language with Clojure-like syntax and semantics based on EoPL + Shift/Reset, implemented in OCaml
Kontlang is a dynamically typed, purely functional (excluding the use of continuations) language interpreted with a CEK-machine-like evaluator, written in a trampolining defunctionalized continuation passing style.
The language supports the following features:
let
,let*
,letfn
,letrec
(each supporting multiple variable bindings in one expression, and mutual recursion in the case ofletrec
)- lexical scope functions with closures
- tail call optimized
- simple dynamic scope macros with expression substitution
- first class modules that can be imported from file
- delimited continuations via the
shift
&reset
operators - standard library modules including implementation of monads via
reify
andreflect
operators - alternative step-wise evaluation interpreter showing expression/value, environment, and continuation at each step
Recommendation for installing dependencies is OPAM
, the defacto standard OCaml package manager.
Once OPAM is installed and configured (opam init
& eval $(opam config env)
- see OPAM website for further details), run:
opam install dune menhir ounit2
This will install all dependencies for kontlang.
Then in the kontlang
repo:
# Running a Read-Eval-Print interpreter
dune exec ./main.exe
or
# Running a Stepwise Execution interpreter
dune exec ./stepwise.exe
Based on examples and exercises from "Introduction to Programming with Shift and Reset" together with reify
and reflect
operators as defined in Andrzej Filinski's "Representing Monads" paper.
Non-deterministic search of numbers matching Pythagorus' Theorem
(let [L Stdlib.ListMonad]
(L.reify
(let [(x (L.reflect (list 1 2 3 4 5)))
(y (L.reflect (list 1 2 3 4 5)))
(z (L.reflect (list 1 2 3 4 5)))]
(if (= (* z z)
(+ (* x x)
(* y y)))
(list x y z)
(L.fail)))))
Above returns ((3 4 5) (4 3 5))
State monad:
(let [S Stdlib.StateMonad]
(S.run_state
(S.reify
(let* [(tick
(fn []
(S.reflect
(fn [state] (cons nil (+ state 1))))))
(_ (tick))
(_ (tick))
(a (S.get))
(_ (tick))]
(- (S.get) a)))
0))
returns a tuple of the "result" and the final state (1 . 3)
See /modules/list-monad.ktl
and /modules/state-monad.ktl
for definitions of the ListMonad and StateMonad modules.
For more usage examples, see the /test
directory.
(reset
(let [(yin ((fn [k] (do [(print "x") k]))
(shift [k] (k k))))
(yang ((fn [k] (do [(print "_") k]))
(shift [k] (k k))))]
(yin yang)))
The above generates an infinite stream on stdout of the form
x_x__x___x____x_____x....