Reference Guide for Calysto Scheme

Calysto Scheme is a real Scheme programming language, with full support for continuations, including call/cc. It can also use all Python libraries. Also has some extensions that make it more useful (stepper-debugger, choose/fail, stack traces), or make it better integrated with Python.

In Jupyter notebooks, because Calysto Scheme uses MetaKernel, it has a fully-supported set of "magics"---meta-commands for additional functionality. This includes running Scheme in parallel. See all of the MetaKernel Magics.

Calysto Scheme is written in Scheme, and then translated into Python (and other backends). The entire functionality lies in a single Python file: https://github.com/Calysto/calysto_scheme/blob/master/calysto_scheme/scheme.py However, you can easily install it (see below).

Please see Calysto Scheme Language for more details on the Calysto Scheme language.

Installation

You can install Calysto Scheme with Python3:

pip3 install --upgrade calysto-scheme --user -U
python3 -m calysto_kernel install --user

or in the system kernel folder with:

sudo pip3 install --upgrade calysto-scheme -U
sudo python3 -m calysto_kernel install

Change pip3/python3 to use a different pip or Python. The version of Python used will determine how Calysto Scheme is run.

Use it in the console, qtconsole, or notebook with IPython 3:

ipython console --kernel calysto_scheme
ipython qtconsole --kernel calysto_scheme
ipython notebook --kernel calysto_scheme

In addition to all of the following items, Calysto Scheme also has access to all of Python's builtin functions, and all of Python's libraries. For example, you can use (complex 3 2) to create a complex number by calling Python's complex function.

Jupyter Enhancements

When you run Calysto Scheme in Jupyter (console, notebook, qtconsole, etc.) you get:

  • TAB completions of Scheme functions and variable names
  • display of rich media
  • stepper/debugger
  • magics (% macros)
  • shell commands (! command)
  • LaTeX equations
  • LaTeX-style variables
  • Python integration

LaTeX-style variables

Calysto Scheme allows you to use LaTeX-style variables in code. For example, if you type:

\beta

with the cursor right after the 'a' in beta, and then press TAB, it will turn into the unicode character:

β

There are nearly 1300 different symbols defined (thanks to the Julia language) and documented here:

http://docs.julialang.org/en/release-0.4/manual/unicode-input/#man-unicode-input

Calysto Scheme may not implement all of those. Some useful and suggestive ones:

  • \pi - π
  • \Pi - Π
  • \Sigma - Σ
  • _i - subscript i, such as vectorᵢ
In [1]:
(define α 67)
In [2]:
α
Out[2]:
67
In [3]:
(define i 2)
(define vectorᵢ (vector-ref (vector 0 6 3 2) i))
vectorᵢ
Out[3]:
3

Rich media

In [4]:
(import "calysto.display")
Out[4]:
(calysto)
In [5]:
(calysto.display.HTML "This is <b>bold</b>, <i>italics</i>, <u>underlined</u>.")
Out[5]:
This is bold, italics, underlined.
In [6]:
(import "calysto.graphics")
Out[6]:
(calysto)
In [7]:
(define canvas (calysto.graphics.Canvas))
In [8]:
(define ball (calysto.graphics.Circle '(150 150) 100))
In [9]:
(ball.draw canvas)
Out[9]:

Shell commands

In [10]:
! ls /tmp
 config-err-xKLxlo
 data.in
 snap.0_canonical-livepatch_T3qk8v
 snap.1000_gimp_sWagwQ
 ssh-CZzILsgWt9Zv
 systemd-private-42d628edc3bb4937ba24e08da9a82866-bolt.service-MRDb9u
 systemd-private-42d628edc3bb4937ba24e08da9a82866-colord.service-GxIyqz
 systemd-private-42d628edc3bb4937ba24e08da9a82866-fwupd.service-uHFZyL
 systemd-private-42d628edc3bb4937ba24e08da9a82866-iio-sensor-proxy.service-MgIq5B
 systemd-private-42d628edc3bb4937ba24e08da9a82866-redis-server.service-eDX0r5
 systemd-private-42d628edc3bb4937ba24e08da9a82866-rtkit-daemon.service-KzoHbL
 systemd-private-42d628edc3bb4937ba24e08da9a82866-systemd-resolved.service-M9b7Fe
 systemd-private-42d628edc3bb4937ba24e08da9a82866-systemd-timesyncd.service-wCU0NV
'Test Dir'
 www-data-temp-aspnet-0

Stepper/Debugger

Here is what the debugger looks like:

It has breakpoints (click in left margin). You must press Stop to exit the debugger.

%%debug

(begin
 (define x 1)
 (set! x 2)
)

Python Integration

You can import and use any Python library in Calysto Scheme.

In addition, if you wish, you can execute expressions and statements in a Python environment:

In [11]:
(python-eval "1 + 2")
Out[11]:
3
In [12]:
(python-exec 
"
def mypyfunc(a, b):
    return a * b
")

This is a shared environment with Scheme:

In [13]:
(mypyfunc 4 5)
Out[13]:
20

You can use func to turn a Scheme procedure into a Python function, and define! to put it into the shared enviornment with Python:

In [14]:
(define! mypyfunc2 (func (lambda (n) n)))
In [15]:
(python-eval "mypyfunc2(34)")
Out[15]:
34

Differences Between Languages

Major differences between Scheme and Python

  1. In Scheme, double quotes are used for strings and may contain newlines
  2. In Scheme, a single quote is short for (quote ...) and means "literal"
  3. In Scheme, everything is an expression and has a return value
  4. Python does not support macros (e.g., extending syntax)
  5. In Python, "if X" is false if X is None, False, [], (,) or 0. In Scheme, "if X" is only false if X is #f or 0
  6. Calysto Scheme uses continuations, not the call stack. However, for debugging there is a pseudo-stack when an error is raised. You can trun that off with (use-stack-trace #f)
  7. Scheme procedures are not Python functions, but there are means to use one as the other.

Major Differences Between Calysto Scheme and other Schemes

  1. define-syntax works slightly differently
  2. In Calysto Scheme, #(...) is short for '#(...)
  3. Calysto Scheme is missing many standard functions (see list at bottom)
  4. Calysto Scheme has a built-in amb operator called choose
  5. For debugging there is a pseudo-stack when errors are raised in Calysto Scheme. You can trun that off with (use-stack-trace #f)

Stack Trace

Calysto Scheme acts as if it has a call stack, for easier debugging. For example:

In [16]:
(define fact
    (lambda (n)
      (if (= n 1)
           q
           (* n (fact (- n 1))))))
In [17]:
(fact 5)

Traceback (most recent call last):
  File "In [17]", line 1, col 1, in 'fact'
  File "In [16]", line 5, col 17, in 'fact'
  File "In [16]", line 5, col 17, in 'fact'
  File "In [16]", line 5, col 17, in 'fact'
  File "In [16]", line 5, col 17, in 'fact'
  File "In [16]", line 4, col 12
RunTimeError: unbound variable 'q'

To turn off the stack trace on error:

(use-stack-trace #f)

That will allow infinite recursive loops without keeping track of the "stack".

Calysto Scheme Variables

SCHEMEPATH

SCHEMEPATH is a list of search directories used with (load NAME). This is a reference, so you should append to it rather than attempting to redefine it.

In [18]:
SCHEMEPATH
Out[18]:
("." "/home/dblank/.local/lib/python3.6/site-packages/calysto_scheme/modules")
In [19]:
(set-cdr! (cdr SCHEMEPATH) (list "/var/modules"))
In [20]:
SCHEMEPATH
Out[20]:
("." "/home/dblank/.local/lib/python3.6/site-packages/calysto_scheme/modules" "/var/modules")

Getting Started

Note that you can use the word lambda or \lambda and then press [TAB]

In [21]:
(define factorial
  (λ (n)
     (cond
      ((zero? n) 1)
      (else (* n (factorial (- n 1)))))))
In [22]:
(factorial 5)
Out[22]:
120

define-syntax

(define-syntax NAME RULES): a method for creating macros

In [23]:
(define-syntax time 
  [(time ?exp) (let ((start (current-time)))
                 ?exp
                 (- (current-time) start))])
In [24]:
(time (car '(1 2 3 4)))
Out[24]:
0.0012819766998291016
In [25]:
;;---------------------------------------------------------------------
;; collect is like list comprehension in Python

(define-syntax collect
  [(collect ?exp for ?var in ?list)
   (filter-map (lambda (?var) ?exp) (lambda (?var) #t) ?list)]
  [(collect ?exp for ?var in ?list if ?condition)
   (filter-map (lambda (?var) ?exp) (lambda (?var) ?condition) ?list)])

(define filter-map
  (lambda (f pred? values)
    (if (null? values)
      '()
      (if (pred? (car values))
          (cons (f (car values)) (filter-map f pred? (cdr values)))
          (filter-map f pred? (cdr values))))))
In [26]:
(collect (* n n) for n in (range 10))
Out[26]:
(0 1 4 9 16 25 36 49 64 81)
In [27]:
(collect (* n n) for n in (range 5 20 3))
Out[27]:
(25 64 121 196 289)
In [28]:
(collect (* n n) for n in (range 10) if (> n 5))
Out[28]:
(36 49 64 81)
In [29]:
;;---------------------------------------------------------------------
;; for loops

(define-syntax for
  [(for ?exp times do . ?bodies)
   (for-repeat ?exp (lambda () . ?bodies))]
  [(for ?var in ?exp do . ?bodies)
   (for-iterate1 ?exp (lambda (?var) . ?bodies))]
  [(for ?var at (?i) in ?exp do . ?bodies)
   (for-iterate2 0 ?exp (lambda (?var ?i) . ?bodies))]
  [(for ?var at (?i ?j . ?rest) in ?exp do . ?bodies)
   (for ?var at (?i) in ?exp do
     (for ?var at (?j . ?rest) in ?var do . ?bodies))])

(define for-repeat
  (lambda (n f)
    (if (< n 1)
      'done
      (begin
        (f)
        (for-repeat (- n 1) f)))))

(define for-iterate1
  (lambda (values f)
    (if (null? values)
      'done
      (begin
        (f (car values))
        (for-iterate1 (cdr values) f)))))

(define for-iterate2
  (lambda (i values f)
    (if (null? values)
      'done
      (begin
        (f (car values) i)
        (for-iterate2 (+ i 1) (cdr values) f)))))
In [30]:
(define matrix2d
  '((10 20)
    (30 40)
    (50 60)
    (70 80)))

(define matrix3d
  '(((10 20 30) (40 50 60))
    ((70 80 90) (100 110 120))
    ((130 140 150) (160 170 180))
    ((190 200 210) (220 230 240))))
In [31]:
(begin 
 (define hello 0)
 (for 5 times do (set! hello (+ hello 1)))
 hello
 )
Out[31]:
5
In [32]:
(for sym in '(a b c d) do (define x 1) (set! x sym) (print x))
a
b
c
d
Out[32]:
done
In [33]:
(for n in (range 10 20 2) do (print n))
10
12
14
16
18
Out[33]:
done
In [34]:
(for n at (i j) in matrix2d do (print (list n 'coords: i j)))
(10 coords: 0 0)
(20 coords: 0 1)
(30 coords: 1 0)
(40 coords: 1 1)
(50 coords: 2 0)
(60 coords: 2 1)
(70 coords: 3 0)
(80 coords: 3 1)
Out[34]:
done
In [35]:
(for n at (i j k) in matrix3d do (print (list n 'coords: i j k)))
(10 coords: 0 0 0)
(20 coords: 0 0 1)
(30 coords: 0 0 2)
(40 coords: 0 1 0)
(50 coords: 0 1 1)
(60 coords: 0 1 2)
(70 coords: 1 0 0)
(80 coords: 1 0 1)
(90 coords: 1 0 2)
(100 coords: 1 1 0)
(110 coords: 1 1 1)
(120 coords: 1 1 2)
(130 coords: 2 0 0)
(140 coords: 2 0 1)
(150 coords: 2 0 2)
(160 coords: 2 1 0)
(170 coords: 2 1 1)
(180 coords: 2 1 2)
(190 coords: 3 0 0)
(200 coords: 3 0 1)
(210 coords: 3 0 2)
(220 coords: 3 1 0)
(230 coords: 3 1 1)
(240 coords: 3 1 2)
Out[35]:
done
In [36]:
(define-syntax scons
  [(scons ?x ?y) (cons ?x (lambda () ?y))])

(define scar car)

(define scdr
  (lambda (s)
    (let ((result ((cdr s))))
      (set-cdr! s (lambda () result))
      result)))

(define first
  (lambda (n s)
    (if (= n 0)
      '()
      (cons (scar s) (first (- n 1) (scdr s))))))

(define nth
  (lambda (n s)
    (if (= n 0)
      (scar s)
      (nth (- n 1) (scdr s)))))

(define smap
  (lambda (f s)
    (scons (f (scar s)) (smap f (scdr s)))))

(define ones (scons 1 ones))

(define nats (scons 0 (combine nats + ones)))

(define combine
  (lambda (s1 op s2)
    (scons (op (scar s1) (scar s2)) (combine (scdr s1) op (scdr s2)))))

(define fibs (scons 1 (scons 1 (combine fibs + (scdr fibs)))))

(define facts (scons 1 (combine facts * (scdr nats))))

(define ! (lambda (n) (nth n facts)))
In [37]:
(! 5)
Out[37]:
120
In [38]:
(nth 10 facts)
Out[38]:
3628800
In [39]:
(nth 20 fibs)
Out[39]:
10946
In [40]:
(first 30 fibs)
Out[40]:
(1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040)

for-each

(for-each PROCEDURE LIST): apply PROCEDURE to each item in LIST; like map but don't return results

In [41]:
(for-each (lambda (n) (print n)) '(3 4 5))
3
4
5

format

(format STRING ITEM ...): format the string with ITEMS as arguments

In [42]:
(format "This uses formatting ~a ~s ~%" 'apple 'apple)
Out[42]:
"This uses formatting apple apple \n"

func

Turns a lambda into a Python function.

(func (lambda ...))

In [43]:
(func (lambda (n) n))
Out[43]:
<function dlr_func.<locals>.f at 0x7fc499d3c2f0>

There's more!

Please see Calysto Scheme Language for more details on the Calysto Scheme language.