Skip to content
A dialect of Lisp extended to support concurrent programming, written in Go.
Branch: master
Clone or download
Latest commit 5f176d2 Aug 8, 2015
Type Name Latest commit message Commit time
Failed to load latest commit information.
constants Add `random' primitive Jul 18, 2014
lexer compatibility with Windows \r Jul 13, 2014
parser Fix `select' bugs and add randomized select ping pong test Jul 18, 2014
tests Add tests.go to pass go1.3 buildings Jul 23, 2014
value Add `random' primitive Jul 18, 2014
LICENSE Update Aug 8, 2015

LispEx Build Status

A dialect of Lisp extended to support concurrent programming.


LispEx is another Lisp Interpreter implemented with Go. The syntax, semantics and library procedures are a subset of R5RS:

LispEx 0.1.0 (Saturday, 19-Jul-14 12:52:45 CST)

;; lambda expression
>>> ((lambda (x y . z) (+ x y (car z))) 1 2 5 11)

;; currying
>>> (define (curry func arg1) (lambda (arg) (apply func arg1 (list arg))))
>>> (map (curry + 2) '(1 2 3 4))
(3 4 5 6)

;; apply
>>> (apply + 1 2 '(3 4))

;; composite function
>>> (define ((compose f g) x) (f (g x)))
>>> (define caar (compose car car))
>>> (caar '((1 2) 3 4))

;; tail recursion 
>>> (letrec 
      ((even? (lambda (n) (if (= 0 n) #t (odd? (- n 1)))))
       (odd?  (lambda (n) (if (= 0 n) #f (even? (- n 1))))))
      (even? 88))

;; multiple nestings of quasiquote 
;; (challenging to have a right implementation)
>>> `(1 `,(+ 1 ,(+ 2 3)) 4)
(1 `,(+ 1 5) 4)
>>> `(1 ```,,@,,@(list (+ 1 2)) 4)
(1 ```,,@,3 4)

;; lazy evaluation
>>> (define f (delay (+ 1)))
>>> (force f)

What's new, the Go-like concurrency features are introduced in LispEx. You can start new coroutines with go statements, and use <-chan or chan<- connecting them. A ping-pong example is shown below:

; define channels
(define ping-chan (make-chan))
(define pong-chan (make-chan))
; define a buffered channel
(define sem (make-chan 2))

(define (ping n)
  (if (> n 0)
      (display (<-chan ping-chan))
      (chan<- pong-chan 'pong)
      (ping (- n 1)))
    (chan<- sem 'exit-ping)))

(define (pong n)
  (if (> n 0)
      (chan<- ping-chan 'ping)
      (display (<-chan pong-chan))
      (pong (- n 1)))
    (chan<- sem 'exit-pong)))

(go (ping 6))  ; start ping-routine
(go (pong 6))  ; start pong-routine

; implement semaphore with channel, waiting for ping-pong finishing
(<-chan sem) (newline)
(<-chan sem) (newline)

; should close channels if you don't need it
(close-chan sem)
(close-chan pong-chan)
(close-chan ping-chan)

; the output will be: ping pong ping pong ... exit-ping exit-pong

Furthermore, select statement is also supported, which is necessary for you to select between multiple channels that working with concurrent routines. Just like Go, the code can be written like this:

(define chan-1 (make-chan))
(define chan-2 (make-chan))

(go (chan<- chan-1 'hello-chan-1))
(go (chan<- chan-2 'hello-chan-2))

  ((<-chan chan-1))
  ((<-chan chan-2))
  (default 'hello-default))

(close-chan chan-1)
(close-chan chan-2)

; the output will be: hello-default, as it will cost some CPU times when a coroutine is lanuched.

In this scenario, default case is chosen since there is no ready data in chan-1 or chan-2 when select statement is intepretered. But such scenario will be changed if we sleep the main thread for a while:

(define chan-1 (make-chan))
(define chan-2 (make-chan))

(go (chan<- chan-1 'hello-chan-1))
(go (chan<- chan-2 'hello-chan-2))

; sleep for 20 millisecond
(sleep 20)

  ((<-chan chan-1))
  ((<-chan chan-2))
  (default 'hello-default))

(close-chan chan-1)
(close-chan chan-2)

; the output will be randomized: hello-chan-1 or hello-chan-2

For more interesting examples, please see files under tests folder.


  • Clean designed code, very easy for you to understand the principle, inspired from yin
  • A concurrent design for lexical scanning, inspired from Rob Pike
  • Builtin routines, channels and other necessary components for concurrent programming
  • Give you a REPL

In developing

  • loop in R5RS
  • tail call optimization
  • type checker

Have a try

git clone
cd LispEx
go build && ./LispEx
LispEx 0.1.0 (Saturday, 19-Jul-14 12:52:45 CST)

From here you can type in forms and you'll get the evaluated expressions back. To interpreter a file:


Lisp is fun, go is fun, concurrency is fun. Hope you will have an extraordinary programming experience with LispEx.



You can’t perform that action at this time.