tablambda 0.6.0.post30.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. tablambda-0.6.0.post30.dev0/.gitignore +247 -0
  2. tablambda-0.6.0.post30.dev0/PKG-INFO +45 -0
  3. tablambda-0.6.0.post30.dev0/README.md +29 -0
  4. tablambda-0.6.0.post30.dev0/pyproject.toml +43 -0
  5. tablambda-0.6.0.post30.dev0/src/tablambda/__init__.py +1 -0
  6. tablambda-0.6.0.post30.dev0/src/tablambda/_analysis.py +92 -0
  7. tablambda-0.6.0.post30.dev0/src/tablambda/_ast.py +289 -0
  8. tablambda-0.6.0.post30.dev0/src/tablambda/_binnat.py +170 -0
  9. tablambda-0.6.0.post30.dev0/src/tablambda/_codec.py +147 -0
  10. tablambda-0.6.0.post30.dev0/src/tablambda/_compiler_artifact.py +50 -0
  11. tablambda-0.6.0.post30.dev0/src/tablambda/_defun_codegen.py +324 -0
  12. tablambda-0.6.0.post30.dev0/src/tablambda/_defun_runtime.py +207 -0
  13. tablambda-0.6.0.post30.dev0/src/tablambda/_defunctionalize.py +455 -0
  14. tablambda-0.6.0.post30.dev0/src/tablambda/_dsl.py +148 -0
  15. tablambda-0.6.0.post30.dev0/src/tablambda/_generated/.gitattributes +5 -0
  16. tablambda-0.6.0.post30.dev0/src/tablambda/_generated/__init__.py +1 -0
  17. tablambda-0.6.0.post30.dev0/src/tablambda/_generated/_generated_defun_compiler_py311.py +7579 -0
  18. tablambda-0.6.0.post30.dev0/src/tablambda/_generated/_generated_defun_compiler_py312.py +7579 -0
  19. tablambda-0.6.0.post30.dev0/src/tablambda/_generated/_generated_defun_compiler_py313.py +7579 -0
  20. tablambda-0.6.0.post30.dev0/src/tablambda/_hoas_latex.py +144 -0
  21. tablambda-0.6.0.post30.dev0/src/tablambda/_latex.py +56 -0
  22. tablambda-0.6.0.post30.dev0/src/tablambda/_prelude.py +163 -0
  23. tablambda-0.6.0.post30.dev0/src/tablambda/_pyast.py +416 -0
  24. tablambda-0.6.0.post30.dev0/src/tablambda/_pybuild.py +315 -0
  25. tablambda-0.6.0.post30.dev0/src/tablambda/_reduce.py +145 -0
  26. tablambda-0.6.0.post30.dev0/src/tablambda/_shape.py +129 -0
  27. tablambda-0.6.0.post30.dev0/src/tablambda/_sugar.py +74 -0
  28. tablambda-0.6.0.post30.dev0/src/tablambda/_typecheck.py +370 -0
  29. tablambda-0.6.0.post30.dev0/tests/__snapshots__/test_binnat.ambr +8 -0
  30. tablambda-0.6.0.post30.dev0/tests/__snapshots__/test_defunctionalize.ambr +76 -0
  31. tablambda-0.6.0.post30.dev0/tests/test_arithmetic.py +82 -0
  32. tablambda-0.6.0.post30.dev0/tests/test_binnat.py +81 -0
  33. tablambda-0.6.0.post30.dev0/tests/test_defunctionalize.py +279 -0
  34. tablambda-0.6.0.post30.dev0/tests/test_hoas_latex.py +30 -0
  35. tablambda-0.6.0.post30.dev0/tests/test_pyast.py +69 -0
  36. tablambda-0.6.0.post30.dev0/tests/test_pybuild.py +108 -0
@@ -0,0 +1,247 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ **/docs/_build/
73
+ **/docs/api/
74
+
75
+ # PyBuilder
76
+ .pybuilder/
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+ .jupyter_ystore.db
82
+
83
+ # IPython
84
+ profile_default/
85
+ ipython_config.py
86
+
87
+ # pyenv
88
+ # For a library or package, you might want to ignore these files since the code is
89
+ # intended to run in multiple environments; otherwise, check them in:
90
+ # .python-version
91
+
92
+ # pipenv
93
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
94
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
95
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
96
+ # install all needed dependencies.
97
+ #Pipfile.lock
98
+
99
+ # UV
100
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
101
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
102
+ # commonly ignored for libraries.
103
+ #uv.lock
104
+
105
+ # poetry
106
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
107
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
108
+ # commonly ignored for libraries.
109
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
110
+ #poetry.lock
111
+ #poetry.toml
112
+
113
+ # pdm
114
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
115
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
116
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
117
+ #pdm.lock
118
+ #pdm.toml
119
+ .pdm-python
120
+ .pdm-build/
121
+
122
+ # pixi
123
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
124
+ #pixi.lock
125
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
126
+ # in the .venv directory. It is recommended not to include this directory in version control.
127
+ .pixi
128
+
129
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
130
+ __pypackages__/
131
+
132
+ # Celery stuff
133
+ celerybeat-schedule
134
+ celerybeat.pid
135
+
136
+ # SageMath parsed files
137
+ *.sage.py
138
+
139
+ # Environments
140
+ .env
141
+ .venv
142
+ env/
143
+ venv/
144
+ ENV/
145
+ env.bak/
146
+ venv.bak/
147
+
148
+ # Spyder project settings
149
+ .spyderproject
150
+ .spyproject
151
+
152
+ # Rope project settings
153
+ .ropeproject
154
+
155
+ # mkdocs documentation
156
+ /site
157
+
158
+ # mypy
159
+ .mypy_cache/
160
+ .dmypy.json
161
+ dmypy.json
162
+
163
+ # Pyre type checker
164
+ .pyre/
165
+
166
+ # pytype static type analyzer
167
+ .pytype/
168
+
169
+ # Cython debug symbols
170
+ cython_debug/
171
+
172
+ # PyCharm
173
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
174
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
175
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
176
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
177
+ #.idea/
178
+
179
+ # Abstra
180
+ # Abstra is an AI-powered process automation framework.
181
+ # Ignore directories containing user credentials, local state, and settings.
182
+ # Learn more at https://abstra.io/docs
183
+ .abstra/
184
+
185
+ # Visual Studio Code
186
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
187
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
188
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
189
+ # you could uncomment the following to ignore the entire vscode folder
190
+ # .vscode/
191
+
192
+ # Ruff stuff:
193
+ .ruff_cache/
194
+
195
+ # PyPI configuration file
196
+ .pypirc
197
+
198
+ # Cursor
199
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
200
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
201
+ # refer to https://docs.cursor.com/context/ignore-files
202
+ .cursorignore
203
+ .cursorindexingignore
204
+
205
+ # Marimo
206
+ marimo/_static/
207
+ marimo/_lsp/
208
+ __marimo__/
209
+
210
+ .direnv/
211
+ .devenv/
212
+ result
213
+
214
+ # devenv/nixago scaffolding regenerated by running `nix develop` in a paper subdirectory
215
+ # (the canonical copies live at the repository root)
216
+ /paper/.envrc
217
+ /paper/.gitattributes
218
+ /paper/.vscode/
219
+
220
+ # LaTeX
221
+ *.pdf
222
+ *.aux
223
+ *.fls
224
+ *.fdb_latexmk
225
+ *.synctex.gz
226
+ *.bbl
227
+ *.blg
228
+ *.out
229
+ *.dvi
230
+ *.xcp
231
+
232
+ # Local data
233
+ data/
234
+ trajectory/
235
+ experiment_results.db
236
+
237
+ .playwright-mcp/
238
+ *.local.*
239
+ .envrc.private
240
+ .pre-commit-config.yaml
241
+
242
+ # nixago: ignore-linked-files
243
+ /.vscode/extensions.json
244
+
245
+ arxiv-submission.tar.gz
246
+ node_modules/
247
+ comment.cut
@@ -0,0 +1,45 @@
1
+ Metadata-Version: 2.4
2
+ Name: tablambda
3
+ Version: 0.6.0.post30.dev0
4
+ Summary: A pure lambda-calculus interpreter that applies tabling to weak-head reduction, folding self-referential terms into finite cyclic graphs
5
+ Project-URL: Repository, https://github.com/Atry/MIXINv2
6
+ Author-email: "Yang, Bo" <yang-bo@yang-bo.com>
7
+ License-Expression: MIT
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Classifier: Programming Language :: Python :: 3.14
12
+ Requires-Python: >=3.11
13
+ Requires-Dist: fixpoints
14
+ Requires-Dist: typing-extensions>=4.1.0
15
+ Description-Content-Type: text/markdown
16
+
17
+ # tablambda
18
+
19
+ [![CI](https://github.com/Atry/tablambda/actions/workflows/ci.yml/badge.svg)](https://github.com/Atry/tablambda/actions/workflows/ci.yml)
20
+ [![PyPI](https://img.shields.io/pypi/v/tablambda)](https://pypi.org/project/tablambda/)
21
+ [![Python versions](https://img.shields.io/pypi/pyversions/tablambda)](https://pypi.org/project/tablambda/)
22
+ ![License: MIT](https://img.shields.io/pypi/l/tablambda)
23
+
24
+ A pure lambda-calculus interpreter and compiler, realizing the semantics of the
25
+ paper `paper/tablambda.tex` and depending on `fixpoints`.
26
+
27
+ ```sh
28
+ pip install tablambda
29
+ ```
30
+
31
+ You write ordinary pure lambda terms, and the interpreter gives them powers a
32
+ pure language normally lacks:
33
+
34
+ - Cyclic and infinite data structures, built and transformed directly, with no
35
+ `letrec`, no added recursion construct, and no mutable references.
36
+ - Automatic memoization and dynamic programming: repeated subproblems are shared
37
+ for you, with no cache written by hand.
38
+ - A diverging loop is detected and returns a meaningless value in finite time
39
+ instead of hanging.
40
+
41
+ The companion compiler turns a term into a standalone Python module, so a program
42
+ written once as a lambda term can also run as compiled code.
43
+
44
+ No parser is provided: terms are built directly in Python, with a small prelude
45
+ of the usual combinators, Church numerals, and Scott-encoded lists.
@@ -0,0 +1,29 @@
1
+ # tablambda
2
+
3
+ [![CI](https://github.com/Atry/tablambda/actions/workflows/ci.yml/badge.svg)](https://github.com/Atry/tablambda/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/tablambda)](https://pypi.org/project/tablambda/)
5
+ [![Python versions](https://img.shields.io/pypi/pyversions/tablambda)](https://pypi.org/project/tablambda/)
6
+ ![License: MIT](https://img.shields.io/pypi/l/tablambda)
7
+
8
+ A pure lambda-calculus interpreter and compiler, realizing the semantics of the
9
+ paper `paper/tablambda.tex` and depending on `fixpoints`.
10
+
11
+ ```sh
12
+ pip install tablambda
13
+ ```
14
+
15
+ You write ordinary pure lambda terms, and the interpreter gives them powers a
16
+ pure language normally lacks:
17
+
18
+ - Cyclic and infinite data structures, built and transformed directly, with no
19
+ `letrec`, no added recursion construct, and no mutable references.
20
+ - Automatic memoization and dynamic programming: repeated subproblems are shared
21
+ for you, with no cache written by hand.
22
+ - A diverging loop is detected and returns a meaningless value in finite time
23
+ instead of hanging.
24
+
25
+ The companion compiler turns a term into a standalone Python module, so a program
26
+ written once as a lambda term can also run as compiled code.
27
+
28
+ No parser is provided: terms are built directly in Python, with a small prelude
29
+ of the usual combinators, Church numerals, and Scott-encoded lists.
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["hatchling", "uv-dynamic-versioning>=0.7.0", "editables"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [tool.hatch.version]
6
+ source = "uv-dynamic-versioning"
7
+
8
+ [tool.uv-dynamic-versioning]
9
+ vcs = "git"
10
+ style = "pep440"
11
+ bump = false
12
+ fallback-version = "0.0.0.dev0"
13
+ metadata = false
14
+
15
+ [project]
16
+ name = "tablambda"
17
+ dynamic = ["version"]
18
+ description = "A pure lambda-calculus interpreter that applies tabling to weak-head reduction, folding self-referential terms into finite cyclic graphs"
19
+ readme = "README.md"
20
+ license = "MIT"
21
+ requires-python = ">=3.11"
22
+ authors = [{ name = "Yang, Bo", email = "yang-bo@yang-bo.com" }]
23
+ classifiers = [
24
+ "Development Status :: 3 - Alpha",
25
+ "License :: OSI Approved :: MIT License",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Programming Language :: Python :: 3.14",
28
+ ]
29
+ dependencies = ["fixpoints", "typing-extensions>=4.1.0"]
30
+
31
+ [project.scripts]
32
+ tablambda-regen-compiler = "tablambda._compiler_artifact:main"
33
+
34
+ [tool.uv]
35
+ sources = { fixpoints = { workspace = true } }
36
+
37
+ [tool.hatch.build.targets.wheel]
38
+ packages = ["src/tablambda"]
39
+ only-include = ["src/tablambda"]
40
+ sources = {"src" = ""}
41
+
42
+ [project.urls]
43
+ Repository = "https://github.com/Atry/MIXINv2"
@@ -0,0 +1 @@
1
+ """A pure lambda-calculus interpreter that applies tabling to weak-head reduction, folding self-referential terms into finite cyclic graphs."""
@@ -0,0 +1,92 @@
1
+ """Specialization analysis written in the lambda-calculus itself.
2
+
3
+ The analysis that decides which sub-terms to specialize is a pure lambda term, run by the
4
+ interpreter on the quoted program, so the calculus analyzes its own programs: a demonstration that
5
+ tabling-based reduction expresses program analysis, not only evaluation. This module holds the
6
+ closedness and depth measures; richer certificates (typability, fuel-bounded normalization) live in
7
+ ``_typecheck`` and ``_reduce`` in the same style.
8
+
9
+ This module is pure lambda calculus: every top-level binding is a ``Builder`` (a ``@curry``-decorated
10
+ ``def`` IS a Builder). The Python-side verdict readers live at the boundary (``_specialize``).
11
+
12
+ ``LOOSE_BOUND`` is a DEPTH-FREE closedness measure, so the interpreter's interning shares it across
13
+ every position: ``LOOSE_BOUND quoted`` takes no binder depth, so ``app(LOOSE_BOUND, sub)`` is the
14
+ SAME node for an interned sub-term and is tabled once; a whole-tree scan is then linear. It returns
15
+ the number of enclosing binders the sub-term needs (the de Bruijn ``loose_bound``): a variable needs
16
+ index+1, an abstraction discharges one (floored at zero by ``PRED``), an application needs the larger
17
+ of the two. A sub-term is closed exactly when it needs none (``IS_CLOSED``).
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ from tablambda._dsl import Builder, app, curry, lam
23
+ from tablambda._prelude import IS_ZERO, PLUS, PRED, SUCC, Y
24
+ from tablambda._sugar import ap
25
+
26
+ # Church arithmetic for the measures (truncated subtraction gives the comparisons).
27
+ _SUBTRACT: Builder = lam(lambda a: lam(lambda b: app(app(b, PRED), a))) # a - b, floored at zero
28
+ _AT_MOST: Builder = lam(lambda a: lam(lambda b: app(IS_ZERO, ap(_SUBTRACT, a, b)))) # a <= b
29
+ _MAX: Builder = lam(lambda a: lam(lambda b: ap(_AT_MOST, a, b, b, a))) # a <= b ? b : a
30
+
31
+ LOOSE_BOUND: Builder = app(Y, lam(lambda self_recursion: lam(lambda quoted: ap(
32
+ quoted,
33
+ lam(lambda index: app(SUCC, index)), # QVar index: needs index+1 enclosing binders
34
+ lam(lambda body: app(PRED, app(self_recursion, body))), # QLam body: discharges one binder
35
+ lam(lambda function: lam(lambda argument: ap(
36
+ _MAX, app(self_recursion, function), app(self_recursion, argument),
37
+ ))), # QApp f a: the larger of the two
38
+ ))))
39
+
40
+ IS_CLOSED: Builder = lam(lambda quoted: app(IS_ZERO, app(LOOSE_BOUND, quoted))) # closed iff needs none
41
+
42
+
43
+ # DEPTH: the nesting depth of a quoted term (a Church numeral), a cheap path-free measure the interner
44
+ # shares per distinct sub-term. It bounds the simple-typability check: running algorithm-W on a large
45
+ # (deep) closed combinator is expensive and the no-GC interner retains every reduction, so a specializer
46
+ # only certifies an island when the sub-term is shallow enough (``depth_at_most``), leaving a deep closed
47
+ # region reconstructed as an interpreted graph rather than flattened to a strict island. The bound only
48
+ # ever makes the certificate MORE conservative (fewer islands), never unsound.
49
+ DEPTH: Builder = app(Y, lam(lambda self_recursion: lam(lambda quoted: ap(
50
+ quoted,
51
+ lam(lambda index: lam(lambda s: lam(lambda z: z))), # QVar: a leaf (depth zero)
52
+ lam(lambda body: app(SUCC, app(self_recursion, body))), # QLam: one deeper
53
+ lam(lambda function: lam(lambda argument: app(SUCC, ap(
54
+ _MAX, app(self_recursion, function), app(self_recursion, argument),
55
+ )))), # QApp: one past the deeper side
56
+ ))))
57
+
58
+
59
+ @curry
60
+ def depth_at_most(bound: Builder, quoted: Builder) -> Builder:
61
+ """``DEPTH quoted <= bound`` (a Church boolean): the shallow-enough certificate."""
62
+ return ap(_AT_MOST, app(DEPTH, quoted), bound)
63
+
64
+
65
+ # NODE_COUNT: the number of Var/Lam/App nodes in a quoted term (a Church numeral), a path-free
66
+ # catamorphism the interner shares per distinct sub-term -- same shape as DEPTH but summing (PLUS) the
67
+ # children instead of taking their MAX. It bounds how big a region may be de-tabled (host-compiled to
68
+ # call-by-need): a small region (<= a bound) loses cross-location tabling at most a constant factor, never
69
+ # exponentially, so the local-call-by-need optimization stays bounded and measurable.
70
+ _ZERO: Builder = lam(lambda s: lam(lambda z: z)) # church 0, the leaf base for the count
71
+
72
+ NODE_COUNT: Builder = app(Y, lam(lambda self_recursion: lam(lambda quoted: ap(
73
+ quoted,
74
+ lam(lambda index: app(SUCC, _ZERO)), # QVar: one node
75
+ lam(lambda body: app(SUCC, app(self_recursion, body))), # QLam: one + body
76
+ lam(lambda function: lam(lambda argument: app(SUCC, ap(
77
+ PLUS, app(self_recursion, function), app(self_recursion, argument),
78
+ )))), # QApp: one + function + argument
79
+ ))))
80
+
81
+
82
+ @curry
83
+ def node_count_at_most(bound: Builder, quoted: Builder) -> Builder:
84
+ """``NODE_COUNT quoted <= bound`` (a Church boolean): the small-enough-to-de-table certificate."""
85
+ return ap(_AT_MOST, app(NODE_COUNT, quoted), bound)
86
+
87
+
88
+ @curry
89
+ def loose_bound_at_most(bound: Builder, quoted: Builder) -> Builder:
90
+ """``LOOSE_BOUND quoted <= bound`` (a Church boolean): the few-free-variables certificate (an open
91
+ region with at most ``bound`` free de Bruijn variables, so its host island is an arity-``bound`` native)."""
92
+ return ap(_AT_MOST, app(LOOSE_BOUND, quoted), bound)