prefscript 1.1__tar.gz → 2.0.2__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.
- {prefscript-1.1 → prefscript-2.0.2}/PKG-INFO +34 -21
- prefscript-2.0.2/README.md +57 -0
- {prefscript-1.1 → prefscript-2.0.2}/pyproject.toml +22 -7
- prefscript-2.0.2/src/prefscript/__init__.py +2 -0
- {prefscript-1.1/src → prefscript-2.0.2/src/prefscript}/ascii7io.py +9 -0
- prefscript-2.0.2/src/prefscript/basicfun.py +72 -0
- prefscript-2.0.2/src/prefscript/cantorpairs/__init__.py +2 -0
- {prefscript-1.1/src/cantorpairs/src → prefscript-2.0.2/src/prefscript/cantorpairs}/cp_ex.py +5 -1
- prefscript-2.0.2/src/prefscript/cantorpairs/cp_ex_alt.py +48 -0
- prefscript-2.0.2/src/prefscript/cantorpairs/src/cantorpairs/__init__.py +2 -0
- prefscript-1.1/src/cantorpairs/src/cantorpairs.py → prefscript-2.0.2/src/prefscript/cantorpairs/src/cantorpairs/cantorpairs_src.py +27 -32
- prefscript-2.0.2/src/prefscript/cantorpairs/src/cantorpairs/ensure.py +29 -0
- prefscript-2.0.2/src/prefscript/codegen.py +187 -0
- prefscript-2.0.2/src/prefscript/examples/00.prfs +1 -0
- prefscript-2.0.2/src/prefscript/examples/01_k_0.prfs +5 -0
- prefscript-2.0.2/src/prefscript/examples/02_k_2.prfs +5 -0
- prefscript-2.0.2/src/prefscript/examples/03_sq.prfs +5 -0
- prefscript-2.0.2/src/prefscript/examples/03_sq_standalone.prfs +7 -0
- prefscript-2.0.2/src/prefscript/examples/04_eq.prfs +4 -0
- prefscript-2.0.2/src/prefscript/examples/05_hw.prfs +5 -0
- prefscript-2.0.2/src/prefscript/examples/06_add_rec.prfs +30 -0
- prefscript-2.0.2/src/prefscript/fundata.py +74 -0
- prefscript-2.0.2/src/prefscript/gnums.py +265 -0
- prefscript-2.0.2/src/prefscript/parser.py +48 -0
- prefscript-2.0.2/src/prefscript/praprepro.py +47 -0
- prefscript-2.0.2/src/prefscript/prefscript.py +141 -0
- prefscript-2.0.2/src/prefscript/pytokr/src/pytokr/__init__.py +153 -0
- prefscript-2.0.2/src/prefscript/script.py +148 -0
- prefscript-2.0.2/src/prefscript/stdprfs/std.prfs +81 -0
- {prefscript-1.1 → prefscript-2.0.2}/src/prefscript.egg-info/PKG-INFO +34 -21
- prefscript-2.0.2/src/prefscript.egg-info/SOURCES.txt +35 -0
- prefscript-2.0.2/src/prefscript.egg-info/entry_points.txt +2 -0
- prefscript-2.0.2/src/prefscript.egg-info/requires.txt +1 -0
- prefscript-2.0.2/src/prefscript.egg-info/top_level.txt +1 -0
- prefscript-1.1/README.md +0 -45
- prefscript-1.1/src/cantorpairs/__init__.py +0 -1
- prefscript-1.1/src/prefscript.egg-info/SOURCES.txt +0 -16
- prefscript-1.1/src/prefscript.egg-info/entry_points.txt +0 -2
- prefscript-1.1/src/prefscript.egg-info/requires.txt +0 -1
- prefscript-1.1/src/prefscript.egg-info/top_level.txt +0 -3
- prefscript-1.1/src/prefscript.py +0 -437
- prefscript-1.1/tests/test.py +0 -17
- prefscript-1.1/tests/test_fact.py +0 -20
- {prefscript-1.1 → prefscript-2.0.2}/LICENSE +0 -0
- {prefscript-1.1 → prefscript-2.0.2}/setup.cfg +0 -0
- {prefscript-1.1 → prefscript-2.0.2}/src/prefscript.egg-info/dependency_links.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: prefscript
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: Partial Recursive Functions for Scripting
|
|
5
5
|
Author-email: José Luis Balcázar <jose.luis.balcazar@upc.edu>
|
|
6
6
|
Project-URL: Homepage, https://github.com/balqui/prefscript
|
|
@@ -8,35 +8,41 @@ Project-URL: Bug Tracker, https://github.com/balqui/prefscript/issues
|
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist:
|
|
14
|
+
Requires-Dist: lark
|
|
15
|
+
Dynamic: license-file
|
|
15
16
|
|
|
16
17
|
# PReFScript:
|
|
17
18
|
## Partial Recursive Functions for Scripting
|
|
18
19
|
|
|
19
|
-
Author: Jose
|
|
20
|
+
Author: Jose Luis Balcazar, ORCID 0000-0003-4248-4528
|
|
20
21
|
|
|
21
22
|
Project started: mid Germinal 2003.
|
|
22
23
|
|
|
23
|
-
Current version: 1.1, late Thermidor 2024.
|
|
24
|
-
|
|
25
24
|
Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
|
|
26
25
|
|
|
27
26
|
A Python-based environment to explore and experiment with partial
|
|
28
27
|
recursive functions; naturally doubles as a (purely functional)
|
|
29
28
|
programming language, but it is not intended to be used much as such.
|
|
30
29
|
|
|
30
|
+
Current version: 2.0.2, late Fructidor 2026. Previous version 1.2
|
|
31
|
+
of mid Messidor 2026 is *incompatible*.
|
|
32
|
+
|
|
31
33
|
### Scripts
|
|
32
34
|
|
|
33
|
-
In PReFScript, a script is a sequence of functions defined
|
|
34
|
-
other and of a few basic functions via the
|
|
35
|
-
of composition and minimization.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
In PReFScript, a script is a sequence of functions defined
|
|
36
|
+
in terms of each other and of a few basic functions via the
|
|
37
|
+
partial recursion rules of composition and minimization.
|
|
38
|
+
All functions are from the natural numbers into the natural
|
|
39
|
+
numbers and may be undefined for some inputs.
|
|
40
|
+
|
|
41
|
+
In order to handle tuples or sequences of natural numbers,
|
|
42
|
+
a Cantor-like encoding is used;
|
|
43
|
+
see <https://github.com/balqui/cantorpairs/blob/main/README.md>.
|
|
44
|
+
|
|
45
|
+
Specifically, the always available basic functions include:
|
|
40
46
|
`k_1`, the constant 1 function;
|
|
41
47
|
`id`, the identity function;
|
|
42
48
|
addition and multiplication, `add` and `mul` respectively,
|
|
@@ -47,14 +53,21 @@ pair `<x.y>` and computes `max(0, x - y)` so that we always stay
|
|
|
47
53
|
within the natural numbers; and two functions related to projections
|
|
48
54
|
of Cantor-encoded sequences.
|
|
49
55
|
|
|
50
|
-
Scripts are maintained in objects of the class PReFScript,
|
|
51
|
-
that can be imported into your own Python program.
|
|
52
|
-
Alternatively, a stand-alone interpreter is also provided.
|
|
53
|
-
Thus, you have available two main ways of programming in PReFScript.
|
|
54
|
-
|
|
55
56
|
### Installation and ways to use PReFScript functions
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
The usual `pip`-based process should work. Differently from
|
|
59
|
+
previous versions, all functionality in 2.0.* is fully compatible
|
|
60
|
+
with a `pipx` installation. You may need to specify `--upgrade`
|
|
61
|
+
flags, depending on your previous installation. LLMs say that
|
|
62
|
+
`uv` should work as well.
|
|
63
|
+
|
|
64
|
+
The current version installs a stand-alone interpreter.
|
|
65
|
+
See [doc.md](https://github.com/balqui/prefscript/blob/main/docs/doc.md).
|
|
66
|
+
|
|
67
|
+
*The following applied to the previous version 1.2*:
|
|
68
|
+
Scripts were maintained in objects of the class PReFScript,
|
|
69
|
+
that could be imported into your own Python program.
|
|
70
|
+
Thus, you had available two main ways of programming in
|
|
71
|
+
PReFScript. All this does not apply anymore to versions 2.0.*.
|
|
59
72
|
|
|
60
73
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# PReFScript:
|
|
2
|
+
## Partial Recursive Functions for Scripting
|
|
3
|
+
|
|
4
|
+
Author: Jose Luis Balcazar, ORCID 0000-0003-4248-4528
|
|
5
|
+
|
|
6
|
+
Project started: mid Germinal 2003.
|
|
7
|
+
|
|
8
|
+
Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
|
|
9
|
+
|
|
10
|
+
A Python-based environment to explore and experiment with partial
|
|
11
|
+
recursive functions; naturally doubles as a (purely functional)
|
|
12
|
+
programming language, but it is not intended to be used much as such.
|
|
13
|
+
|
|
14
|
+
Current version: 2.0.2, late Fructidor 2026. Previous version 1.2
|
|
15
|
+
of mid Messidor 2026 is *incompatible*.
|
|
16
|
+
|
|
17
|
+
### Scripts
|
|
18
|
+
|
|
19
|
+
In PReFScript, a script is a sequence of functions defined
|
|
20
|
+
in terms of each other and of a few basic functions via the
|
|
21
|
+
partial recursion rules of composition and minimization.
|
|
22
|
+
All functions are from the natural numbers into the natural
|
|
23
|
+
numbers and may be undefined for some inputs.
|
|
24
|
+
|
|
25
|
+
In order to handle tuples or sequences of natural numbers,
|
|
26
|
+
a Cantor-like encoding is used;
|
|
27
|
+
see <https://github.com/balqui/cantorpairs/blob/main/README.md>.
|
|
28
|
+
|
|
29
|
+
Specifically, the always available basic functions include:
|
|
30
|
+
`k_1`, the constant 1 function;
|
|
31
|
+
`id`, the identity function;
|
|
32
|
+
addition and multiplication, `add` and `mul` respectively,
|
|
33
|
+
that interpret the single number received as the Cantor encoding
|
|
34
|
+
of a pair `<x.y>` and compute the corresponding operation on `x` and
|
|
35
|
+
`y`; modified difference `diff` that receives likewise a Cantor-encoded
|
|
36
|
+
pair `<x.y>` and computes `max(0, x - y)` so that we always stay
|
|
37
|
+
within the natural numbers; and two functions related to projections
|
|
38
|
+
of Cantor-encoded sequences.
|
|
39
|
+
|
|
40
|
+
### Installation and ways to use PReFScript functions
|
|
41
|
+
|
|
42
|
+
The usual `pip`-based process should work. Differently from
|
|
43
|
+
previous versions, all functionality in 2.0.* is fully compatible
|
|
44
|
+
with a `pipx` installation. You may need to specify `--upgrade`
|
|
45
|
+
flags, depending on your previous installation. LLMs say that
|
|
46
|
+
`uv` should work as well.
|
|
47
|
+
|
|
48
|
+
The current version installs a stand-alone interpreter.
|
|
49
|
+
See [doc.md](https://github.com/balqui/prefscript/blob/main/docs/doc.md).
|
|
50
|
+
|
|
51
|
+
*The following applied to the previous version 1.2*:
|
|
52
|
+
Scripts were maintained in objects of the class PReFScript,
|
|
53
|
+
that could be imported into your own Python program.
|
|
54
|
+
Thus, you had available two main ways of programming in
|
|
55
|
+
PReFScript. All this does not apply anymore to versions 2.0.*.
|
|
56
|
+
|
|
57
|
+
|
|
@@ -1,24 +1,39 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["setuptools
|
|
2
|
+
requires = ["setuptools>=68.0"]
|
|
3
3
|
build-backend = "setuptools.build_meta"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "prefscript"
|
|
7
|
-
version = "
|
|
8
|
-
authors = [
|
|
7
|
+
version = "2.0.2"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "José Luis Balcázar", email = "jose.luis.balcazar@upc.edu" }
|
|
10
|
+
]
|
|
9
11
|
description = "Partial Recursive Functions for Scripting"
|
|
10
12
|
readme = "README.md"
|
|
11
|
-
requires-python = ">=3.
|
|
13
|
+
requires-python = ">=3.12"
|
|
12
14
|
classifiers = [
|
|
13
15
|
"Programming Language :: Python :: 3",
|
|
14
16
|
"License :: OSI Approved :: MIT License",
|
|
15
17
|
"Operating System :: OS Independent",
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
dependencies = [
|
|
21
|
+
"lark",
|
|
22
|
+
]
|
|
18
23
|
|
|
19
24
|
[project.urls]
|
|
20
25
|
"Homepage" = "https://github.com/balqui/prefscript"
|
|
21
26
|
"Bug Tracker" = "https://github.com/balqui/prefscript/issues"
|
|
22
27
|
|
|
23
28
|
[project.scripts]
|
|
24
|
-
prefscript = "prefscript:
|
|
29
|
+
prefscript = "prefscript.prefscript:main"
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.packages.find]
|
|
32
|
+
where = ["src"]
|
|
33
|
+
|
|
34
|
+
[tool.setuptools.package-data]
|
|
35
|
+
prefscript = [
|
|
36
|
+
"stdprfs/*.prfs",
|
|
37
|
+
"examples/*.prfs",
|
|
38
|
+
]
|
|
39
|
+
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
'''
|
|
2
|
+
Project started mid Germinal 2023:
|
|
3
|
+
PReFScript: A Partial Recursive Functions Lab
|
|
4
|
+
|
|
5
|
+
Ancillary module, early Thermidor 2024:
|
|
2
6
|
Single-integer encoding and decoding of (printable) 7-bit ASCII strings
|
|
7
|
+
Currently employed for versions up to 1.2, this docstring expanded
|
|
8
|
+
by mid Messidor 2026 with no change to code.
|
|
9
|
+
|
|
10
|
+
Author: Jose L Balcazar, ORCID 0000-0003-4248-4528
|
|
11
|
+
Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
|
|
3
12
|
'''
|
|
4
13
|
|
|
5
14
|
TWO_pow_7 = 1 << 7
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Project started mid Germinal 2003:
|
|
3
|
+
PReFScript: A Partial Recursive Functions Lab
|
|
4
|
+
|
|
5
|
+
Module version early Thermidor 2026:
|
|
6
|
+
basicfun: class BasicFun to have everything that concerns the list
|
|
7
|
+
of basic functions in a single place. A dict of FunData.
|
|
8
|
+
|
|
9
|
+
Author: Jose L Balcazar, ORCID 0000-0003-4248-4528
|
|
10
|
+
Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
|
|
11
|
+
'''
|
|
12
|
+
|
|
13
|
+
from . import cantorpairs as cp
|
|
14
|
+
from .fundata import FunData
|
|
15
|
+
|
|
16
|
+
class BasicFun(dict):
|
|
17
|
+
'''
|
|
18
|
+
Dictionary with the info required for each basic function.
|
|
19
|
+
'''
|
|
20
|
+
def __init__(self):
|
|
21
|
+
dict.__init__(self)
|
|
22
|
+
|
|
23
|
+
self["k_1"] = FunData(
|
|
24
|
+
"k_1",
|
|
25
|
+
"The constant 1 function",
|
|
26
|
+
"basic", tuple(),
|
|
27
|
+
"lambda x: 1", cp.dp(0, 0))
|
|
28
|
+
|
|
29
|
+
self["id"] = FunData(
|
|
30
|
+
"id",
|
|
31
|
+
"The identity function",
|
|
32
|
+
"basic", tuple(),
|
|
33
|
+
"lambda x: x", cp.dp(0, 1))
|
|
34
|
+
|
|
35
|
+
self["s_tup"] = FunData(
|
|
36
|
+
"s_tup",
|
|
37
|
+
"Single-argument version of suffix tuple",
|
|
38
|
+
"basic", tuple(),
|
|
39
|
+
"lambda x: cp.s_tup(cp.pr_L(x), cp.pr_R(x))", cp.dp(0, 2))
|
|
40
|
+
|
|
41
|
+
self["proj"] = FunData(
|
|
42
|
+
"proj",
|
|
43
|
+
"Single-argument version of projection",
|
|
44
|
+
"basic", tuple(),
|
|
45
|
+
"lambda x: cp.pr(cp.pr_L(x), cp.pr_R(x))", cp.dp(0, 3))
|
|
46
|
+
|
|
47
|
+
self["add"] = FunData(
|
|
48
|
+
"add",
|
|
49
|
+
"Addition x+y of the two components of input <x.y>",
|
|
50
|
+
"basic", tuple(),
|
|
51
|
+
"lambda x: cp.pr_L(x) + cp.pr_R(x)", cp.dp(0, 4))
|
|
52
|
+
|
|
53
|
+
self["mul"] = FunData(
|
|
54
|
+
"mul",
|
|
55
|
+
"Multiplication x*y of the two components of input <x.y>",
|
|
56
|
+
"basic", tuple(),
|
|
57
|
+
"lambda x: cp.pr_L(x) * cp.pr_R(x)", cp.dp(0, 5))
|
|
58
|
+
|
|
59
|
+
self["diff"] = FunData(
|
|
60
|
+
"diff",
|
|
61
|
+
"Modified difference max(0, x-y) of the two components of input <x.y>",
|
|
62
|
+
"basic", tuple(),
|
|
63
|
+
"lambda x: max(0, cp.pr_L(x) - cp.pr_R(x))", cp.dp(0, 6))
|
|
64
|
+
|
|
65
|
+
def showgnums(self):
|
|
66
|
+
for f in sorted(self, key = lambda x: cp.pr_R(self[x].index)):
|
|
67
|
+
i = cp.pr_R(self[f].index)
|
|
68
|
+
print(f"{i}: {self[f].fname}, {self[f].docst}, Goedel number <0.{i}> = {self[f].index}")
|
|
69
|
+
|
|
70
|
+
if __name__ == "__main__":
|
|
71
|
+
BasicFun().showgnums()
|
|
72
|
+
|
|
@@ -7,7 +7,7 @@ Ancillary functions for the Partial Recursive Functions lab.
|
|
|
7
7
|
Examples of usage of pairing and tupling.
|
|
8
8
|
'''
|
|
9
9
|
|
|
10
|
-
import cantorpairs as cp
|
|
10
|
+
import src.cantorpairs as cp
|
|
11
11
|
|
|
12
12
|
for i in range(4):
|
|
13
13
|
for j in range(4):
|
|
@@ -35,4 +35,8 @@ while t:
|
|
|
35
35
|
print(t, cp.pr_L(t))
|
|
36
36
|
t = cp.pr_R(t)
|
|
37
37
|
|
|
38
|
+
cp.Ensure().that('a' == 'a', "'a' is OK")
|
|
39
|
+
z = 54321
|
|
40
|
+
print(f"Sequence {z} is {cp.seq(z)}")
|
|
41
|
+
cp.Ensure().that('a' == 'b', "'a' is not 'b'")
|
|
38
42
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Author: Jose L Balcazar, ORCID 0000-0003-4248-4528, april 2023 onwards
|
|
3
|
+
Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
|
|
4
|
+
|
|
5
|
+
Ancillary functions for the Partial Recursive Functions lab.
|
|
6
|
+
|
|
7
|
+
Examples of usage of pairing and tupling.
|
|
8
|
+
|
|
9
|
+
MOVE THIS FILE ONE LEVEL UP IN THE FILE TREE BEFORE RUNNING.
|
|
10
|
+
|
|
11
|
+
Adjacent file cp_ex.py has the right import to run here.
|
|
12
|
+
'''
|
|
13
|
+
|
|
14
|
+
import cantorpairs as cp
|
|
15
|
+
|
|
16
|
+
for i in range(4):
|
|
17
|
+
for j in range(4):
|
|
18
|
+
print(i, j, cp.dp(i, j))
|
|
19
|
+
|
|
20
|
+
for i in range(90, 100):
|
|
21
|
+
print(cp.pr_L(i), cp.pr_R(i), cp.dp(cp.pr_L(i), cp.pr_R(i)), i)
|
|
22
|
+
|
|
23
|
+
t = cp.tup_e(4, 7, 56, 101)
|
|
24
|
+
for i in range(5):
|
|
25
|
+
'last call is actually out of range'
|
|
26
|
+
print(cp.pr(t, i))
|
|
27
|
+
|
|
28
|
+
st = cp.s_tup(t, 2)
|
|
29
|
+
print(st)
|
|
30
|
+
for i in range(3):
|
|
31
|
+
print(cp.pr(st, i))
|
|
32
|
+
|
|
33
|
+
while t:
|
|
34
|
+
print(t, cp.pr_L(t))
|
|
35
|
+
t = cp.pr_R(t)
|
|
36
|
+
|
|
37
|
+
t = cp.tup_i(range(8, 16))
|
|
38
|
+
while t:
|
|
39
|
+
print(t, cp.pr_L(t))
|
|
40
|
+
t = cp.pr_R(t)
|
|
41
|
+
|
|
42
|
+
cp.Ensure().that('a' == 'a', "'a' is OK")
|
|
43
|
+
z = 54321
|
|
44
|
+
print(f"Sequence {z} is {cp.seq(z)}")
|
|
45
|
+
|
|
46
|
+
# ~ cp.Ensure().that('a' == 'b', "'a' is not 'b'")
|
|
47
|
+
|
|
48
|
+
cp.ensure.that(1 == 2, "no kidding...")
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
'''
|
|
2
|
-
|
|
2
|
+
Project started: mid Germinal 2023.
|
|
3
|
+
Current version: 1.2, late Fructidor 2026.
|
|
4
|
+
Not pip-installable as of today.
|
|
5
|
+
See README at `https://github.com/balqui/cantorpairs`.
|
|
6
|
+
|
|
7
|
+
Author: Jose L Balcazar, ORCID 0000-0003-4248-4528
|
|
3
8
|
Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
|
|
4
9
|
|
|
5
10
|
Ancillary functions for PReFScript, the Partial Recursive Functions lab.
|
|
@@ -9,9 +14,7 @@ adapted from `https://en.wikipedia.org/wiki/Pairing_function`
|
|
|
9
14
|
The dotted pair is a bijection between `NxN` and `N-{0}`:
|
|
10
15
|
the natural number zero is used as "nil".
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
Current version: 0.2, early Thermidor 2024.
|
|
14
|
-
Not pip-installable as of today. See README at `https://github.com/balqui/cantorpairs`
|
|
17
|
+
See files cp_ex*.py for usage examples.
|
|
15
18
|
|
|
16
19
|
After each push, the following extra incantation is most likely
|
|
17
20
|
necessary in the local copy of the git repo for `prefscript`:
|
|
@@ -19,41 +22,18 @@ necessary in the local copy of the git repo for `prefscript`:
|
|
|
19
22
|
'''
|
|
20
23
|
|
|
21
24
|
from functools import cache
|
|
22
|
-
from math import isqrt
|
|
25
|
+
from math import isqrt # instead of math.sqrt
|
|
23
26
|
|
|
24
|
-
__version__ = "
|
|
27
|
+
__version__ = "1.2"
|
|
25
28
|
|
|
26
29
|
@cache
|
|
27
30
|
def _isqrt(n):
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# ~ def _isqrt(n):
|
|
31
|
-
# ~ '''
|
|
32
|
-
# ~ int square root via binary search, own program
|
|
33
|
-
# ~ because math.sqrt fails with big numbers, e.g. the
|
|
34
|
-
# ~ decoding of dp(10, 10^17) comes out wrong.
|
|
35
|
-
# ~ '''
|
|
36
|
-
# ~ def rr(n, k):
|
|
37
|
-
# ~ """
|
|
38
|
-
# ~ Pre: k <= sqrt(n)
|
|
39
|
-
# ~ Post: a <= sqrt(n) < b and b - a = k
|
|
40
|
-
# ~ """
|
|
41
|
-
# ~ if 4*k*k > n:
|
|
42
|
-
# ~ return k, 2*k
|
|
43
|
-
# ~ a, b = rr(n, 2*k)
|
|
44
|
-
# ~ m = (a + b)//2 # m = a + k
|
|
45
|
-
# ~ if m*m <= n:
|
|
46
|
-
# ~ return m, b
|
|
47
|
-
# ~ else:
|
|
48
|
-
# ~ return a, m
|
|
49
|
-
# ~ assert n >= 0
|
|
50
|
-
# ~ if n == 0:
|
|
51
|
-
# ~ return 0
|
|
52
|
-
# ~ return rr(n, 1)[0]
|
|
31
|
+
"Formerly used to switch between various sqrt programs"
|
|
32
|
+
return isqrt(n)
|
|
53
33
|
|
|
54
34
|
@cache
|
|
55
35
|
def _unpair(z):
|
|
56
|
-
"local sq root
|
|
36
|
+
"uses local sq root"
|
|
57
37
|
assert z > 0
|
|
58
38
|
w = (_isqrt(8*(z - 1) + 1) - 1)//2
|
|
59
39
|
t = (w*w + w)//2
|
|
@@ -115,3 +95,18 @@ def pr(t, k):
|
|
|
115
95
|
returns zero (meaning end of tuple) if k is too large
|
|
116
96
|
'''
|
|
117
97
|
return pr_L(s_tup(t, k))
|
|
98
|
+
|
|
99
|
+
def proj(t, k):
|
|
100
|
+
'''
|
|
101
|
+
projection function, alternative name
|
|
102
|
+
'''
|
|
103
|
+
return pr(t, k)
|
|
104
|
+
|
|
105
|
+
def seq(z):
|
|
106
|
+
"list form of the sequence encoded by z"
|
|
107
|
+
ls = list()
|
|
108
|
+
while z != 0:
|
|
109
|
+
ls.append(pr_L(z))
|
|
110
|
+
z = pr_R(z)
|
|
111
|
+
return ls
|
|
112
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Project started: mid Germinal 2023.
|
|
3
|
+
This module started: early Fructidor 2026.
|
|
4
|
+
Current version: 1.0.
|
|
5
|
+
Not pip-installable as of today.
|
|
6
|
+
See README at `https://github.com/balqui/cantorpairs`
|
|
7
|
+
|
|
8
|
+
Author: Jose L Balcazar, ORCID 0000-0003-4248-4528
|
|
9
|
+
Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
|
|
10
|
+
|
|
11
|
+
Ancillary functions for PReFScript, the Partial Recursive Functions lab.
|
|
12
|
+
|
|
13
|
+
Implements a variant of "assert" that is not disabled from the command line.
|
|
14
|
+
See files cp_ex*.py for usage examples.
|
|
15
|
+
|
|
16
|
+
After each push, the following extra incantation is most likely
|
|
17
|
+
necessary in the local copy of the git repo for `prefscript`:
|
|
18
|
+
`git submodule update --remote`
|
|
19
|
+
'''
|
|
20
|
+
|
|
21
|
+
class Ensure:
|
|
22
|
+
|
|
23
|
+
class Failed(Exception): pass
|
|
24
|
+
|
|
25
|
+
def that(cls, assertion, message):
|
|
26
|
+
if not assertion:
|
|
27
|
+
raise cls.Failed(message)
|
|
28
|
+
|
|
29
|
+
ensure = Ensure()
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Project started mid Germinal 2003:
|
|
3
|
+
PReFScript: A Partial Recursive Functions Lab
|
|
4
|
+
|
|
5
|
+
Module version early Fructidor 2026:
|
|
6
|
+
Lark-based code generator, makes the script for PReFScript 2.0 onwards.
|
|
7
|
+
|
|
8
|
+
Author: Jose L Balcazar, ORCID 0000-0003-4248-4528
|
|
9
|
+
Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_
|
|
10
|
+
'''
|
|
11
|
+
|
|
12
|
+
from lark import Transformer, v_args
|
|
13
|
+
from pathlib import Path # for handling imported files
|
|
14
|
+
|
|
15
|
+
from .cantorpairs import ensure
|
|
16
|
+
from .fundata import FunData
|
|
17
|
+
from .parser import prfsparser
|
|
18
|
+
from .script import PReFScript # for the recursive calls on imports
|
|
19
|
+
|
|
20
|
+
# A handful of ancillary functions
|
|
21
|
+
|
|
22
|
+
def funfactgen():
|
|
23
|
+
"function name factory generator, get names by calling funfact"
|
|
24
|
+
i = 69
|
|
25
|
+
while True:
|
|
26
|
+
yield f"___{i}"
|
|
27
|
+
i += 1
|
|
28
|
+
|
|
29
|
+
funfact = funfactgen().__next__
|
|
30
|
+
|
|
31
|
+
def seemsfactgen(nm):
|
|
32
|
+
return nm.startswith('___') and nm[3:].isdigit()
|
|
33
|
+
|
|
34
|
+
FILENAMES = set() # main and imported in order to
|
|
35
|
+
# avoid import cycles - a bit ugly,
|
|
36
|
+
# consider designing some other way
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@v_args(inline=True)
|
|
40
|
+
class ScriptMaker(Transformer):
|
|
41
|
+
'''
|
|
42
|
+
Instances of transformers traverse the AST in postorder.
|
|
43
|
+
They need one method for each sort of tree node, that is,
|
|
44
|
+
grammar label; these methods receive the transformed
|
|
45
|
+
subtrees and must return the transformed current node.
|
|
46
|
+
|
|
47
|
+
The v_args decorator allows the methods in the Transformer
|
|
48
|
+
instance to avoid the "children" tuple and refer directly
|
|
49
|
+
to the subtree funspec's.
|
|
50
|
+
|
|
51
|
+
ScriptMaker objects contain a local PReFScript that is
|
|
52
|
+
"in construction": they transform each AST 'funspec' node into
|
|
53
|
+
a FunData which gets added to the script, returning its name.
|
|
54
|
+
Imports are handled via recursive calls on a fresh script that
|
|
55
|
+
gets added to the script under construction afterwards.
|
|
56
|
+
|
|
57
|
+
The 'program' simply returns the finally constructed script.
|
|
58
|
+
|
|
59
|
+
Instead of inheriting the name, we set up surrogates and
|
|
60
|
+
leave for later the name change if convenient.
|
|
61
|
+
'''
|
|
62
|
+
|
|
63
|
+
def __init__(self, script, filename, import_folder = None, imported = False):
|
|
64
|
+
"filename must be an already resolved Path()"
|
|
65
|
+
super().__init__(self)
|
|
66
|
+
self.script = script
|
|
67
|
+
self.imported = imported
|
|
68
|
+
if import_folder is not None:
|
|
69
|
+
self.import_folder = Path(import_folder)
|
|
70
|
+
else:
|
|
71
|
+
self.import_folder = None
|
|
72
|
+
self.filename = filename
|
|
73
|
+
FILENAMES.add(self.filename)
|
|
74
|
+
|
|
75
|
+
def ascii_const(self, strconst):
|
|
76
|
+
nm = funfact()
|
|
77
|
+
fdat = FunData(nm, howdf = "ascii_const", defon = (strconst,))
|
|
78
|
+
self.script.define(fdat)
|
|
79
|
+
return nm
|
|
80
|
+
|
|
81
|
+
def single(self, cname):
|
|
82
|
+
nm = cname.value
|
|
83
|
+
ensure.that(not seemsfactgen(nm), f"Error: name {nm} is disallowed.")
|
|
84
|
+
if nm not in self.script:
|
|
85
|
+
self.script.define(FunData(nm))
|
|
86
|
+
return nm
|
|
87
|
+
|
|
88
|
+
def parenth(self, same):
|
|
89
|
+
return same
|
|
90
|
+
|
|
91
|
+
def comp(self, left, right):
|
|
92
|
+
nm = funfact()
|
|
93
|
+
fdat = FunData(nm, howdf = "comp", defon = (left, right))
|
|
94
|
+
self.script.define(fdat)
|
|
95
|
+
return nm
|
|
96
|
+
|
|
97
|
+
def pair(self, left, right):
|
|
98
|
+
nm = funfact()
|
|
99
|
+
fdat = FunData(nm, howdf = "pair", defon = (left, right))
|
|
100
|
+
self.script.define(fdat)
|
|
101
|
+
return nm
|
|
102
|
+
|
|
103
|
+
def mu(self, test):
|
|
104
|
+
nm = funfact()
|
|
105
|
+
fdat = FunData(nm, howdf = "mu", defon = (test,))
|
|
106
|
+
self.script.define(fdat)
|
|
107
|
+
return nm
|
|
108
|
+
|
|
109
|
+
def rec(self, recurse, base, is_base):
|
|
110
|
+
nm = funfact()
|
|
111
|
+
fdat = FunData(nm, howdf = "rec", defon = (recurse, base, is_base))
|
|
112
|
+
self.script.define(fdat)
|
|
113
|
+
return nm
|
|
114
|
+
|
|
115
|
+
def program(self, *imports_and_defuns):
|
|
116
|
+
return self.script
|
|
117
|
+
|
|
118
|
+
def docstring(self, *docstrings):
|
|
119
|
+
"They are tokens, but somehow each can be handled as string"
|
|
120
|
+
return ' '.join(ds.strip('"') for ds in docstrings)
|
|
121
|
+
|
|
122
|
+
def defun(self, cname, docstring, alias):
|
|
123
|
+
"First two cases after skipping main are functions already in the script"
|
|
124
|
+
nm = cname.value
|
|
125
|
+
if nm == "main" and self.imported:
|
|
126
|
+
"silently ignore it"
|
|
127
|
+
return ''
|
|
128
|
+
if seemsfactgen(alias):
|
|
129
|
+
"name to override"
|
|
130
|
+
fspec = self.script[alias]
|
|
131
|
+
if docstring:
|
|
132
|
+
ensure.that(not fspec.docst,
|
|
133
|
+
f"Unexpectedly found already a previous docstring in {nm}.")
|
|
134
|
+
fspec.docst = docstring
|
|
135
|
+
fspec.fname = nm
|
|
136
|
+
self.script.remove(alias)
|
|
137
|
+
elif nm in self.script:
|
|
138
|
+
"pending name to be completed"
|
|
139
|
+
ensure.that(self.script[nm].howdf == "pending",
|
|
140
|
+
f"Seems that you have two defs of {self.script[nm]}.")
|
|
141
|
+
self.script.remove(nm) # o/w defining it will fail
|
|
142
|
+
fspec = FunData(nm, docst = docstring,
|
|
143
|
+
howdf = "alias", defon = (alias,))
|
|
144
|
+
else:
|
|
145
|
+
fspec = FunData(nm, docst = docstring,
|
|
146
|
+
howdf = "alias", defon = (alias,))
|
|
147
|
+
self.script.define(fspec)
|
|
148
|
+
return nm
|
|
149
|
+
|
|
150
|
+
def importing(self, filename):
|
|
151
|
+
|
|
152
|
+
def attempt(candidate, filename, cnt):
|
|
153
|
+
"try candidate folder, careful with std.prfs"
|
|
154
|
+
path = (candidate / filename).resolve()
|
|
155
|
+
if path.exists():
|
|
156
|
+
ensure.that(filename != "std.prfs" or cnt == 0,
|
|
157
|
+
"Presence of a nonstandard std.prfs file in " +
|
|
158
|
+
f"path {path} is disallowed.")
|
|
159
|
+
return path
|
|
160
|
+
|
|
161
|
+
filename = filename.strip('"')
|
|
162
|
+
if not filename.endswith(".prfs"):
|
|
163
|
+
filename += ".prfs"
|
|
164
|
+
|
|
165
|
+
import_folders = list()
|
|
166
|
+
if self.import_folder is not None:
|
|
167
|
+
import_folders.append(self.import_folder)
|
|
168
|
+
import_folders.append(self.filename.parent)
|
|
169
|
+
import_folders.append(Path(__file__).parent / "stdprfs")
|
|
170
|
+
|
|
171
|
+
importpath = None
|
|
172
|
+
cnt = len(import_folders)
|
|
173
|
+
for candidate in import_folders:
|
|
174
|
+
"ordered search for the imported file"
|
|
175
|
+
cnt -= 1
|
|
176
|
+
importpath = attempt(candidate, filename, cnt)
|
|
177
|
+
if importpath is not None:
|
|
178
|
+
break
|
|
179
|
+
ensure.that(importpath is not None,
|
|
180
|
+
f"Did not find {filename} to import.")
|
|
181
|
+
if importpath not in FILENAMES:
|
|
182
|
+
FILENAMES.add(importpath)
|
|
183
|
+
local_ast = prfsparser(open(importpath).read())
|
|
184
|
+
local_scrmk = ScriptMaker(PReFScript(), importpath, imported = True)
|
|
185
|
+
local_scr = local_scrmk.transform(local_ast)
|
|
186
|
+
self.script |= local_scr
|
|
187
|
+
return ''
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
main: id
|