Compare commits
No commits in common. "f67d1e273075d18c2c495c2a6d70c3c6bfabe7e4" and "602bf5298342a433a62a8c7a1f3a16250d1bd88c" have entirely different histories.
f67d1e2730
...
602bf52983
103
README.md
103
README.md
@ -1,95 +1,24 @@
|
|||||||
# Lamb: A Lambda Calculus Engine
|
# Lamb: A Lambda Calculus Engine
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
### Method 1: PyPi (not yet)
|
|
||||||
1. Put this on PyPi
|
|
||||||
2. Write these instructions
|
|
||||||
|
|
||||||
### Method 2: Git
|
|
||||||
1. Clone this repository.
|
|
||||||
2. Make and enter a [virtual environment](https://docs.python.org/3/library/venv.html).
|
|
||||||
3. ``cd`` into this directory
|
|
||||||
4. Run ``pip install .``
|
|
||||||
5. Run ``python .``
|
|
||||||
|
|
||||||
-------------------------------------------------
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Type lambda expressions into the prompt, and Lamb will evaluate them. \
|
|
||||||
Use your `\` (backslash) key to type a `λ`. \
|
|
||||||
To define macros, use `=`. For example,
|
|
||||||
```
|
|
||||||
~~> T = λab.a
|
|
||||||
~~> F = λab.a
|
|
||||||
~~> NOT = λa.a F T
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that there are spaces in `λa.a F T`. With no spaces, `aFT` will be parsed as one variable. \
|
|
||||||
Lambda functions can only take single-letter, lowercase arguments. `λA.A` is not valid syntax. \
|
|
||||||
Unbound variables (upper and lower case) that aren't macros will become free variables.
|
|
||||||
|
|
||||||
Be careful, macros are case-sensitive. If you define a macro `MAC` and accidentally write `mac` in the prompt, `mac` will become a free variable.
|
|
||||||
|
|
||||||
Numbers will automatically be converted to Church numerals. For example, the following line will reduce to `T`.
|
|
||||||
```
|
|
||||||
~~> 3 NOT F
|
|
||||||
```
|
|
||||||
|
|
||||||
If an expression takes too long to evaluate, you may interrupt reduction with `Ctrl-C`.
|
|
||||||
|
|
||||||
-------------------------------------------------
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
Lamb comes with a few commands. Prefix them with a `:`
|
|
||||||
|
|
||||||
`:help` Prints a help message
|
|
||||||
|
|
||||||
`:clear` Clear the screen
|
|
||||||
|
|
||||||
`:rlimit [int | None]` Set maximum reduction limit. `:rlimit none` sets no limit.
|
|
||||||
|
|
||||||
`:macros` List macros in the current environment.
|
|
||||||
|
|
||||||
`:mdel [macro]` Delete a macro
|
|
||||||
|
|
||||||
`:save [filename]`\
|
|
||||||
`:load [filename]` Save or load the current environment to a file. The lines in a file look exactly the same as regular entries in the prompt, but must only contain macro definitions.
|
|
||||||
|
|
||||||
-------------------------------------------------
|
|
||||||
|
|
||||||
## Internals
|
|
||||||
|
|
||||||
Lamb treats each λ expression as a binary tree. Variable binding and reduction are all simple operations on that tree. All the magic happens inside [`nodes.py`](./lamb/nodes.py).
|
|
||||||
|
|
||||||
**Highlights:**
|
|
||||||
- `TreeWalker` is the iterator we (usually) use to traverse our tree. It walks the "perimeter" of the tree, visiting some nodes multiple times.
|
|
||||||
- `Node` is the base class for all nodes. Any node has `.left` and `.right` elements, which may be `None` (empty). `Node`s also reference their parent and their direction relative to their parent, to make tree traversal easy.
|
|
||||||
- Before any reduction is done, variables are bound via `bind_variables`. This prevents accidental conflicts common in many lambda parsers.
|
|
||||||
|
|
||||||
-------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
## Todo (pre-release):
|
## Todo (pre-release):
|
||||||
- Make command output accessible in prompt
|
- $\alpha$-equivalence check
|
||||||
- Prettyprint functions and rename bound variables
|
- Prettyprint functions (rename bound variables)
|
||||||
- Prettier colors
|
- Write a nice README
|
||||||
- Prevent macro-chaining recursion
|
- Fix colors
|
||||||
- step-by-step reduction
|
- Print macro content if only a macro is typed
|
||||||
- Show a warning when a free variable is created
|
|
||||||
- PyPi package
|
|
||||||
|
|
||||||
|
|
||||||
## Todo:
|
## Todo:
|
||||||
- Command-line options (load a file, run a set of commands)
|
- History accessible in prompt
|
||||||
- $\alpha$-equivalence check
|
- Command and macro autocomplete
|
||||||
- Unchurch macro: make church numerals human-readable
|
- step-by-step reduction
|
||||||
- Full-reduce option (expand all macros)
|
|
||||||
- Print macro content if only a macro is typed
|
|
||||||
- Smart alignment in all printouts
|
|
||||||
- Syntax highlighting: parenthesis, bound variables, macros, etc
|
- Syntax highlighting: parenthesis, bound variables, macros, etc
|
||||||
|
- PyPi package
|
||||||
|
- Smart alignment in all printouts
|
||||||
|
- Full-reduce option
|
||||||
|
- Free variable warning
|
||||||
|
|
||||||
|
## Mention in Docs
|
||||||
|
- lambda functions only work with single-letter arguments
|
||||||
|
- church numerals
|
||||||
|
- how to install
|
@ -84,7 +84,6 @@ class TreeWalker:
|
|||||||
class Node:
|
class Node:
|
||||||
"""
|
"""
|
||||||
Generic class for an element of an expression tree.
|
Generic class for an element of an expression tree.
|
||||||
All nodes are subclasses of this.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -452,6 +451,8 @@ def bind_variables(node: Node, *, ban_macro_name = None) -> None:
|
|||||||
|
|
||||||
# If this expression is part of a macro,
|
# If this expression is part of a macro,
|
||||||
# make sure we don't reference it inside itself.
|
# make sure we don't reference it inside itself.
|
||||||
|
#
|
||||||
|
# TODO: A chain of macros could be used to work around this. Fix that!
|
||||||
if isinstance(n, Macro) and ban_macro_name is not None:
|
if isinstance(n, Macro) and ban_macro_name is not None:
|
||||||
if n.name == ban_macro_name:
|
if n.name == ban_macro_name:
|
||||||
raise ReductionError("Macro cannot reference self")
|
raise ReductionError("Macro cannot reference self")
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 98 KiB |
@ -1,21 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "Lamb"
|
name = "Lamb"
|
||||||
description = "A lambda calculus engine"
|
description = "A lambda calculus engine"
|
||||||
|
version = "0.0.0"
|
||||||
# We use the standard semantic versioning:
|
|
||||||
# maj.min.pat
|
|
||||||
#
|
|
||||||
# Major release:
|
|
||||||
# 1.0.0 is the first stable release.
|
|
||||||
# Incremented on BIG breaking changes.
|
|
||||||
#
|
|
||||||
# Minor release:
|
|
||||||
# Large bug fixes, new features
|
|
||||||
#
|
|
||||||
# Patch release:
|
|
||||||
# Small, compatible fixes.
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"prompt-toolkit==3.0.31",
|
"prompt-toolkit==3.0.31",
|
||||||
"pyparsing==3.0.9"
|
"pyparsing==3.0.9"
|
||||||
|
Reference in New Issue
Block a user