Yet another scheme dialect written in Clojure and ClojureScript

429 阅读1分钟

Lisp is good at meta-programming, Clojure as a new dialect of Lisp, brings power of Lisp into JVM world. Scheme.clj is an attempt to implement Scheme in Clojure(Script). It isn't a complete R5Rs implementation, only partial operator and feature are supported, for which you can check out at Live Demo part.

How it works

Eval-Apply cycle

In case of you not having read the wonderful book SICP, I will firstly explain the famous eval-apply cycle.

eval-apply cycle

Eval-apply cycle is the core of every programming language:

Expressions to be evaluated in environments are reduced to procedures to be applied to arguments, which in turn are reduced to new expressions to be evaluated in new environments, and so on, until we get down to symbols, whose values are looked up in the environment, and to primitive procedures, which are applied directly.

For example, in order to eval expression (+ 1 2) in global env, the evaluator will call add with arguments 1 and 2, which in turns to eval symbol +, 1 and 2 in another env (called closure); Now every expression is self-evaled, so 3 is returned as last value.

Live Demo

Thanks to klipse, We can run scheme.clj in browser !

Init scheme.clj


  (ns my.scheme
    (:require [scheme.core :refer [eval]]))

Number


(map eval
    ["1"
     "(> 3 4)"
     "(< 3 4)"
     "(= 3 4)"
     "(+ 3 4)"
     "(- 3 4)"
     "(* 3 4)"
     "(/ 3 4)"])

String


(map eval
    ["\"hello scheme.clj\""
     "(str \"foo \" \"FOO\")"
     "(= \"FOO\" \"FOO\")"
     ])

Define


(map eval
    ["(define foo 2)"
     "foo"])

Flow control


(eval "(if (> 3 2) 3 2)")

Lambda


(map eval
    ["((lambda (x y) (+ y x)) 1 2)"
     "(define (my-add x y) (+ y x))"
     "(my-add 1 2)"
     "(((lambda (x y) (+ x y)) 1) 2)"  ;; currying
     "(let ((x 1) (y 2))  (+ x y))"    ;; let is just a syntax sugar of lambda
     ])
 

Pair


(map eval
    ["(cons 1 2)"
     "(list 1 2)"
     "nil"                   ;; empty list, same to (list)
     "(cons 1 nil)"          ;; same to (list 1)
     "(car (cons 1 2))"
     "(cdr (cons 1 2))"
     "(car (list 1 2))"
     "(cdr (list 1 2))"
     "(null? (list))"
     ])