Metadata-Version: 2.4
Name: compact-scheme
Version: 0.0.4
Summary: Tiny implementation of scheme in Python
Author-email: Chandru Subramanian <hello@chandru.blog>
License: Apache-2.0
Project-URL: Repository, https://github.com/thechandru/compact
Project-URL: Documentation, https://thechandru.github.io/compact/
Keywords: scheme,lisp,interpreter,embedded,interop
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastcore
Dynamic: license-file

# compact


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

Lisp is well-suited for symbolic computation. Since it represents code and data identically (homoiconicity), it makes it trivial to embed problem-specific semantics and language inside a Lisp program. Lisp programs manipulate (evaluate and apply) lists. Since Lisp programs are themselves lists, they can “rewrite themselves”.

Languages are limited by their syntax. For instance, if you wanted to introduce a new construct, it is usually clumsy to add new constructs into the language. However, because of the way Lisp handles symbols, adding a new form is just “business as usual” in Lisp.

Lisp seems to strongly suggest expressing the program in language that is precise for the problem being solved. So if you don’t have suitable nouns or verbs, just make them up and extend the language!

Scheme is a dialect of Lisp. There is disagreement on the direction of Lisp variants (mostly across Common Lisp and Scheme). We prefer Scheme because it has a simpler symbol model (the tl;dr is that in Common Lisp, functions live in different namespaces than variables, in Scheme they are the same).

## What is compact

`compact` is a library that enables Python programmers to use Lisp inside their Python code. `compact` supports a version of Scheme. `compact` does not aim to comply with any standards (like R5RS, R7RS etc.).

`compact` shares the namespace with Python. Symbols defined in Lisp are accessible in Python. Lisp can also access any symbols defined in Python.

> [!NOTE]
>
> **compact** /ˈkäm-ˌpakt/
>
> *verb*
>
> 1.  exert force on something so that it becomes more dense; compress
> 2.  make or enter into a formal agreement with another party or parties
>
> *noun*
>
> 1.  something that is compact or compacted
> 2.  an agreement or covenant between two or more parties

A Python program can use Lisp by importing the `lisp` singleton and evaluating Lisp code through it.

``` python
from compact import lisp
```

``` python
"(/ 22.0 7)" @ lisp
```

    3.142857142857143

`"(expr)" @ lisp` evaluates a Lisp expression against the calling Python frame’s globals — Python variables are visible in Lisp, and anything `define`d in Lisp lands back in Python as a regular variable. Python functions are callable from Lisp directly; Lisp functions are callable from Python.

``` python
a, b = 3, 4
"(define c (sqrt (+ (* a a) (* b b))))" @ lisp
c
```

    5.0

One stated barrier to wider adoption of Lisp is limited library availability (say, compared to Python). `compact` sidesteps the library problem by embedding Lisp inside Python via a shared namespace. Specifically, `compact` shares the calling module’s globals().

``` python
import math
pi = math.pi
"(define (area r) (* pi r r))" @ lisp
sorted(map(area, [1, 2, 3, 4, 5]))
```

    [3.141592653589793,
     12.566370614359172,
     28.274333882308138,
     50.26548245743669,
     78.53981633974483]

Since Lisp programs rely heavily on recursion, it is common to implement *Tail Call Optimization* (TCO). This effectively converts tail-recursive calls into an iteration, avoiding stack overflow.

``` python
"""
(define (factorial n acc)
  (if (= n 0) acc
      (factorial (- n 1) (* n acc))))
""" @ lisp

l10k = factorial(10000, 1)

import math
m10k = math.factorial(10000)

l10k == m10k
```

    True

As mentioned earlier, one of the powerful aspects of Lisp is the ability to invent syntax. A good example is looping constructs - by default we don’t provide any. If you needed a special form of iterator, you could implement it as a Lisp macro and it would be indistinguishable from the rest of the language.

``` python
"""
  (define while
    (macro (cond . body)
      `(let loop () (when ,cond ,@body (loop)))))
""" @ lisp

"""
  (let ((i 0) (acc 0))
    (while (< i 5)
      (set! acc (+ acc i))
      (set! i (+ i 1)))
    acc) 
""" @ lisp
```

    10

Lisp symbols with hyphens are not valid Python identifiers. `lisp[name]` looks up any symbol in the Lisp environment — including user-defined ones.

``` python
import math
pi = math.pi

"""
(define (sphere-volume r)  (* (/ 4.0 3) pi r r r))
(define (sphere-surface r) (* 4 pi r r))
""" @ lisp

# lisp symbols can use characters that are disallowed in Python
# the can be accessed using lisp[...]
lisp['sphere-volume'](5), lisp['sphere-surface'](5)
```

    (523.5987755982989, 314.1592653589793)

## Install

``` sh
pip install compact-scheme
```

## LLM reference

For LLM-assisted development, a compact reference of supported forms, primitives, and usage is available at [llms.txt](llms.txt).

For a full walkthrough of supported forms and primitives with examples, see [core examples](examples/core.ipynb).
