/skim

Scheme syntax for Clojure-inspired concise programming

Primary LanguageSchemeMIT LicenseMIT

# Skim

Skim makes Scheme a little more Clojure-esque. How?

Skim offers flatter syntax for bindings, conditionals, and function definitions.

(define (fib n)
  (cond ((zero? n) 0)
        ((= n 1) 1)
        (else (+ (fib (- n 1)) (fib (- n 2))))))

Becomes:

(defn fib #(n)
  (cind (zero? n) 0
        (= n 1) 1
        else (+ (fib (- n 1)) (fib (- n 2)))))

And this:

(define (sum-squares a b)
  (let ((a2 (* a a))
        (b2 (* b b)))
    (+ a2 b2)))

Becomes:

(defn sum-squares #(a b)
  (lit #(a2 (* a a)
         b2 (* b b))
    (+ a2 b2)))

Named-let also gets slimmed down:

(defn factorial #(n)
  (lip iter
      #(i 1 product 1)
    (if (= i n)
        product
        (iter (+ i 1) (* i product)))))

Clojure's `for` form is fully supported:

(fir #(x '(1 2 3 13)
       y #(7 8)
       lit: #(z (* x y))
       when: (odd? z)
       lit: #(a (* 2 z))
       while: (< a 170))
     (/ a 3))

Expands to:

(let iter-1 ((in-1 (cursor '(1 2 3 13))) (out '()))
  (if (cursor-null? in-1)
    (let ((_ (cursor-next (cursor '()))) (out out))
      (reverse out))
    (let ((x (cursor-value in-1)))
      (let iter ((in (cursor '#(7 8))) (out out))
        (if (cursor-null? in)
          (iter-1 (cursor-next in-1) out)
          (let* ((y (cursor-value in)) (z (* x y)))
            (if (odd? z)
              (let ((a (* 2 z)))
                (if (< a 170)
                  (iter (cursor-next in) (cons (/ a 3) out))
                  (reverse out)))
              (iter (cursor-next in) out))))))))

`For` depends on `cursor`, a procedure that allows lists and vectors
to be iterated upon. `Cursor-value`, `cursor-next`, and `cursor-null?`
are used to get the current cursor value, advance the cursor position,
and detect end-of-collection conditions.

Clojure-style multiple signature function definitions are available
using Shinn's pattern matching library. (For both anonymous procedures
and definitions using `fn` and `defn`, respectively.)

(defn add "Add number(s)"
  (#(x) x)
  (#(x y) (+ x y)))

(fn #(x) (+ x 1))

Additionally, `->` and `-->` syntax are supported.

Here's an example that uses `defn`, `lip`, and `cind`:

(defn sum
  "Add all integers from 0 to `n` inclusive"
  #(n)
  (lip iter #(n n sum 0)
       (cind (> n 0)
             (iter (- n 1) (+ sum n))
             else
             sum)))

Why the weird names? Because it's important that you continue to be
able to write plain-old Scheme. Because including Skim shouldn't
change the meaning of existing code.