Compare commits

..

17 Commits

Author SHA1 Message Date
5bff77e4a7 Merge branch 'master' of https://github.com/rm-dr/lamb 2023-11-27 14:23:00 -08:00
8c8ea69890 Update README.md 2023-11-27 14:21:13 -08:00
6d14333e52 Update README.md 2023-11-27 14:19:24 -08:00
ab9057148a Merge branch 'master' of ssh://git.betalupi.com:33/Mark/lamb 2023-10-17 18:37:38 -07:00
c07edf1b50 Updated README.md 2023-10-16 21:17:27 -07:00
1bb0b91e20 Fixed a link in README 2023-10-16 15:31:49 -07:00
b20604de5c Fixed a path 2023-10-10 22:08:07 -07:00
d2f8b1c8fb Updated version 2023-04-02 20:54:26 -07:00
3022c2ffc0 Removed type hints to support older python versions 2023-04-02 20:52:59 -07:00
acbc247e10 Merge branch 'master' of ssh://git.betalupi.com:33/Mark/lamb 2023-04-02 07:56:55 -07:00
907d2d9e79 Added links to readme 2023-04-02 07:55:37 -07:00
73f4c60c06 Updated install instructions 2023-03-30 20:29:29 -07:00
fe7e6fca13 Added social media banner 2023-01-09 17:36:49 -08:00
866cb64485 Updated links 2023-01-09 17:15:52 -08:00
09a389857a Hide time when reducing by steps 2022-11-12 19:31:12 -08:00
da997b80c7 Added demo script 2022-11-12 19:15:08 -08:00
1b951813f4 Fixed command parser 2022-11-12 19:14:58 -08:00
11 changed files with 184 additions and 53 deletions

3
.gitignore vendored
View File

@ -9,4 +9,5 @@ build
dist dist
# Misc # Misc
*.gif *.gif
misc/secrets.sh

View File

@ -8,6 +8,7 @@
"mdel", "mdel",
"onefile", "onefile",
"Packrat", "Packrat",
"printables",
"pyparsing", "pyparsing",
"rlimit", "rlimit",
"runstatus", "runstatus",

View File

@ -1,14 +1,27 @@
# Lamb: A Lambda Calculus Engine # 🐑 Lamb: A Lambda Calculus Engine
If you're reading this on PyPi, go [here](https://git.betalupi.com/Mark/lamb). ![Lamb Demo](https://github.com/rm-dr/lamb/assets/96270320/d518e344-e7c8-47ed-89c4-7ce273bf4e2d)
![Lamb demo](https://betalupi.com/static/git/lambdemo.gif)
## Installation
## :brain: What is lambda calculus?
- [video 1](https://www.youtube.com/watch?v=3VQ382QG-y4): Introduction and boolean logic. The first few minutes are a bit confusing, but it starts to make sense at about [`6:50`](https://youtu.be/3VQ382QG-y4?t=400)
- [video 2](https://www.youtube.com/watch?v=pAnLQ9jwN-E): Continuation of video 1. Features combinators and numerals.
- [blog](https://www.driverlesscrocodile.com/technology/lambda-calculus-for-people-a-step-behind-me-1): Another introduction. Moves slower than the two videos above and doesn't assume CS knowledge. Four-part series.
- [handout](https://static.betalupi.com/ormc/Advanced/Lambda%20Calculus.pdf): A handout I've written on lambda calculus.
## :package: Installation
### Method 1: [PyPi](https://pypi.org/project/lamb-engine) ### Method 1: [PyPi](https://pypi.org/project/lamb-engine)
1. *(Optional but recommended)* make and enter a [venv](https://docs.python.org/3/library/venv.html). 1. *(Optional but recommended)* make and enter a [venv](https://docs.python.org/3/library/venv.html)
- **On Windows, run the following in cmd or powershell:**
- `cd Desktop`
- `python -m venv lamb`
- `.\Scripts\activate`
2. `pip install lamb-engine` 2. `pip install lamb-engine`
3. `lamb` 3. `lamb`
@ -21,10 +34,10 @@ If you're reading this on PyPi, go [here](https://git.betalupi.com/Mark/lamb).
------------------------------------------------- -------------------------------------------------
## Usage ## 📖 Usage
Type lambda expressions into the prompt, and Lamb will evaluate them. \ Type expressions into the prompt, and Lamb will evaluate them. \
Use your `\` (backslash) key to type a `λ`. \ Use your `\` (backslash) key to type a `λ`. \
To define macros, use `=`. For example, To define macros, use `=`. For example,
``` ```
@ -63,7 +76,7 @@ Have fun!
------------------------------------------------- -------------------------------------------------
## Commands ## :card_file_box: Commands
Lamb understands many commands. Prefix them with a `:` in the prompt. Lamb understands many commands. Prefix them with a `:` in the prompt.
@ -100,8 +113,7 @@ The lines in a file look exactly the same as regular entries in the prompt, but
- Cleanup warnings - Cleanup warnings
- Truncate long expressions in warnings - Truncate long expressions in warnings
- Loop detection - Loop detection
- α-equivalence check
- Unchurch command: make church numerals human-readable - Unchurch command: make church numerals human-readable
- Better Syntax highlighting - Better syntax highlighting
- Complete file names and commands - Tab-complete file names and commands
- Tests - Load default macros without manually downloading `macros.lamb` (via `requests`, maybe?)

View File

@ -77,8 +77,8 @@ class Node:
self.parent_side: Direction = None # type: ignore self.parent_side: Direction = None # type: ignore
# Left and right nodes, None if empty # Left and right nodes, None if empty
self._left: Node | None = None self._left = None
self._right: Node | None = None self._right = None
# The runner this node is attached to. # The runner this node is attached to.
# Set by Node.set_runner() # Set by Node.set_runner()
@ -341,7 +341,7 @@ class Bound(EndNode):
# The name of the macro this bound came from. # The name of the macro this bound came from.
# Always equal to self.name, unless the macro # Always equal to self.name, unless the macro
# this came from had a subscript. # this came from had a subscript.
self.macro_name: str | None = macro_name self.macro_name = macro_name
if forced_id is None: if forced_id is None:
self.identifier = bound_counter self.identifier = bound_counter
@ -381,9 +381,9 @@ class Func(Node):
Func.from_parse(result) Func.from_parse(result)
) )
def __init__(self, input: Macro | Bound, output: Node, *, runner = None) -> None: def __init__(self, input, output: Node, *, runner = None) -> None:
super().__init__() super().__init__()
self.input: Macro | Bound = input self.input = input
self.left: Node = output self.left: Node = output
self.right: None = None self.right: None = None
self.runner = runner # type: ignore self.runner = runner # type: ignore

View File

@ -56,7 +56,7 @@ class LambdaParser:
(self.lp + self.pp_history + self.rp) (self.lp + self.pp_history + self.rp)
) )
self.pp_command = pp.Suppress(":") + pp.Word(pp.alphas + "_") + pp.Word(pp.alphas + pp.nums + "_.")[0, ...] self.pp_command = pp.Suppress(":") + pp.Word(pp.alphas + "_") + pp.Word(pp.printables)[0, ...]
self.pp_all = ( self.pp_all = (

View File

@ -14,7 +14,7 @@ help_texts = {}
def lamb_command( def lamb_command(
*, *,
command_name: str | None = None, command_name = None,
help_text: str help_text: str
): ):
""" """

View File

@ -46,7 +46,7 @@ class Runner:
# Maximum amount of reductions. # Maximum amount of reductions.
# If None, no maximum is enforced. # If None, no maximum is enforced.
# Must be at least 1. # Must be at least 1.
self.reduction_limit: int | None = 1_000_000 self.reduction_limit = 1_000_000
# Ensure bound variables are unique. # Ensure bound variables are unique.
# This is automatically incremented whenever we make # This is automatically incremented whenever we make
@ -74,7 +74,7 @@ class Runner:
message = self.prompt_message message = self.prompt_message
) )
def parse(self, line) -> tuple[lamb_engine.nodes.Root | MacroDef | Command, list]: def parse(self, line): # -> tuple[lamb_engine.nodes.Root | MacroDef | Command, list]
e = self.parser.parse_line(line) e = self.parser.parse_line(line)
w = [] w = []
@ -196,24 +196,31 @@ class Runner:
] ]
else: else:
if not self.step_reduction:
out_text += [
("class:ok", f"Runtime: "),
("class:text", f"{time.time() - start_time:.03f} seconds"),
("class:text", "\n")
]
out_text += [ out_text += [
("class:ok", f"Runtime: "), ("class:ok", f"Exit reason: "),
("class:text", f"{time.time() - start_time:.03f} seconds"),
("class:ok", f"\nExit reason: "),
stop_reason.value, stop_reason.value,
("class:text", "\n"),
("class:ok", f"\nMacro expansions: "), ("class:ok", f"Macro expansions: "),
("class:text", f"{macro_expansions:,}"), ("class:text", f"{macro_expansions:,}"),
("class:text", "\n"),
("class:ok", f"\nReductions: "), ("class:ok", f"Reductions: "),
("class:text", f"{k:,}\t"), ("class:text", f"{k:,}\t"),
("class:muted", f"(Limit: {self.reduction_limit:,})") ("class:muted", f"(Limit: {self.reduction_limit:,})")
] ]
if self.full_expansion: if self.full_expansion:
out_text += [ out_text += [
("class:ok", "\nAll macros have been expanded") ("class:text", "\n"),
("class:ok", "All macros have been expanded")
] ]
if ( if (

View File

@ -1,11 +1,4 @@
# How to use this: # See makedemo.sh
# install vhs
# enter venv
# vhs < misc/demo.tape
#
# We need macros.lamb, so run this from
# the root of this repository.
#Output lambdemo.mp4 #Output lambdemo.mp4
Output lambdemo.gif Output lambdemo.gif
@ -25,7 +18,7 @@ Enter
Sleep 2000ms Sleep 2000ms
# Demo 1: load # Demo 1: load
Type ":load macros.lamb" Type ":load ../macros.lamb"
Sleep 500ms Sleep 500ms
Enter Enter
Sleep 2000ms Sleep 2000ms

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 30 KiB

34
misc/makedemo.sh Executable file
View File

@ -0,0 +1,34 @@
#!/bin/bash
# Should be run from the misc directory.
# Will not work with any other root.
# Create this file.
# Should define two variables:
# DAV_USER="name:password"
# DAV_URL="https://site.com/dav-path"
if [[ -f "secrets.sh" ]]; then
source secrets.sh
else
echo "Cannot run without secrets.sh"
exit
fi
# Activate venv if not in venv
if [[ "$VIRTUAL_ENV" == "" ]]; then
source ../venv/bin/activate
fi
# Make sure our venv is running the latest
# version of lamb.
pip install --editable ..
# Make gif
vhs < demo.tape
# Upload
curl \
--user $DAV_USER \
--url $DAV_URL \
--upload-file "lambdemo.gif"

View File

@ -15,7 +15,7 @@ lamb = "lamb_engine:main"
[project] [project]
name = "lamb_engine" name = "lamb_engine"
description = "A lambda calculus engine" description = "A lambda calculus engine"
version = "1.1.6" version = "1.1.9"
dependencies = [ dependencies = [
"prompt-toolkit==3.0.31", "prompt-toolkit==3.0.31",
"pyparsing==3.0.9" "pyparsing==3.0.9"