curryparty 0.3.0__tar.gz → 0.3.1__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.
- {curryparty-0.3.0 → curryparty-0.3.1}/PKG-INFO +1 -1
- {curryparty-0.3.0 → curryparty-0.3.1}/pyproject.toml +2 -1
- {curryparty-0.3.0 → curryparty-0.3.1}/src/curryparty/__init__.py +4 -4
- {curryparty-0.3.0 → curryparty-0.3.1}/src/curryparty/core.py +30 -22
- {curryparty-0.3.0 → curryparty-0.3.1}/README.md +0 -0
- {curryparty-0.3.0 → curryparty-0.3.1}/src/curryparty/display.py +0 -0
- {curryparty-0.3.0 → curryparty-0.3.1}/src/curryparty/py.typed +0 -0
- {curryparty-0.3.0 → curryparty-0.3.1}/src/curryparty/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "curryparty"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.1"
|
|
4
4
|
description = "Python playground to learn lambda calculus"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -20,4 +20,5 @@ dev = [
|
|
|
20
20
|
"marimo>=0.18.4",
|
|
21
21
|
"polars>=1.36.1",
|
|
22
22
|
"ruff>=0.14.8",
|
|
23
|
+
"tuna>=0.5.11",
|
|
23
24
|
]
|
|
@@ -44,7 +44,7 @@ class Term:
|
|
|
44
44
|
return Term(compose(self.nodes, other.nodes))
|
|
45
45
|
|
|
46
46
|
def beta(self) -> Optional["Term"]:
|
|
47
|
-
candidates = find_redexes(self.nodes)
|
|
47
|
+
candidates = find_redexes(self.nodes).first().collect()
|
|
48
48
|
if len(candidates) == 0:
|
|
49
49
|
return None
|
|
50
50
|
_redex, lamb, b = candidates.row(0)
|
|
@@ -72,14 +72,14 @@ class Term:
|
|
|
72
72
|
Generates an HTML representation that toggles visibility between
|
|
73
73
|
a static state and a SMIL animation on hover using pure CSS.
|
|
74
74
|
"""
|
|
75
|
-
candidates = find_redexes(self.nodes)
|
|
75
|
+
candidates = find_redexes(self.nodes).first().collect()
|
|
76
76
|
if len(candidates) == 0:
|
|
77
77
|
return self._repr_html_()
|
|
78
78
|
|
|
79
79
|
_redex, lamb, b = candidates.row(0)
|
|
80
80
|
new_nodes = beta_reduce(self.nodes, lamb, b)
|
|
81
|
-
vars = find_variables(self.nodes, lamb)["id"]
|
|
82
|
-
b_subtree = subtree(self.nodes, b)
|
|
81
|
+
vars = find_variables(self.nodes, lamb).collect()["id"]
|
|
82
|
+
b_subtree = subtree(self.nodes, b).collect()
|
|
83
83
|
height = min(compute_height(self.nodes), compute_height(new_nodes)) * 2
|
|
84
84
|
if count_variables(self.nodes) == 0:
|
|
85
85
|
return "no width"
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import polars as pl
|
|
2
2
|
from polars import Schema, UInt32
|
|
3
|
-
from polars.functions.lazy import coalesce
|
|
4
3
|
|
|
5
4
|
SCHEMA = Schema(
|
|
6
5
|
{
|
|
@@ -21,7 +20,7 @@ def _shift(nodes: pl.DataFrame, offset: int):
|
|
|
21
20
|
)
|
|
22
21
|
|
|
23
22
|
|
|
24
|
-
def compose(f: pl.DataFrame, x: pl.DataFrame):
|
|
23
|
+
def compose(f: pl.DataFrame, x: pl.DataFrame) -> pl.DataFrame:
|
|
25
24
|
n = len(f)
|
|
26
25
|
return pl.concat(
|
|
27
26
|
[
|
|
@@ -35,31 +34,32 @@ def compose(f: pl.DataFrame, x: pl.DataFrame):
|
|
|
35
34
|
)
|
|
36
35
|
|
|
37
36
|
|
|
38
|
-
def find_redexes(nodes: pl.DataFrame):
|
|
39
|
-
parents = nodes.filter(pl.col("ref").is_null())
|
|
37
|
+
def find_redexes(nodes: pl.DataFrame) -> pl.LazyFrame:
|
|
40
38
|
return (
|
|
41
|
-
|
|
39
|
+
nodes.lazy()
|
|
42
40
|
.filter(
|
|
43
41
|
pl.col("arg").is_not_null(),
|
|
44
|
-
pl.col("
|
|
45
|
-
pl.col("
|
|
42
|
+
pl.col("arg").shift(-1).is_null(),
|
|
43
|
+
pl.col("ref").shift(-1).is_null(),
|
|
46
44
|
)
|
|
47
|
-
.select(
|
|
45
|
+
.select("id", lamb=pl.col("id") + 1, arg="arg")
|
|
48
46
|
)
|
|
49
47
|
|
|
50
48
|
|
|
51
|
-
def find_variables(nodes: pl.DataFrame, lamb: int):
|
|
52
|
-
return nodes.filter(pl.col("ref") == lamb).select("id", replaced=True)
|
|
49
|
+
def find_variables(nodes: pl.DataFrame, lamb: int) -> pl.LazyFrame:
|
|
50
|
+
return nodes.lazy().filter(pl.col("ref") == lamb).select("id", replaced=True)
|
|
53
51
|
|
|
54
52
|
|
|
55
|
-
def subtree(nodes: pl.DataFrame, root: int) -> pl.
|
|
53
|
+
def subtree(nodes: pl.DataFrame, root: int) -> pl.LazyFrame:
|
|
54
|
+
refs = nodes["ref"]
|
|
55
|
+
args = nodes["arg"]
|
|
56
56
|
rightmost = root
|
|
57
57
|
while True:
|
|
58
|
-
ref =
|
|
59
|
-
arg = nodes["arg"][rightmost]
|
|
58
|
+
ref = refs[rightmost]
|
|
60
59
|
if ref is not None:
|
|
61
|
-
return nodes.filter(pl.col("id").is_between(root, rightmost))
|
|
60
|
+
return nodes.lazy().filter(pl.col("id").is_between(root, rightmost))
|
|
62
61
|
|
|
62
|
+
arg = args[rightmost]
|
|
63
63
|
rightmost = arg if arg is not None else rightmost + 1
|
|
64
64
|
|
|
65
65
|
|
|
@@ -77,52 +77,60 @@ def beta_reduce(nodes: pl.DataFrame, lamb: int, b: int) -> pl.DataFrame:
|
|
|
77
77
|
a = lamb + 1
|
|
78
78
|
|
|
79
79
|
vars = find_variables(nodes, lamb)
|
|
80
|
+
|
|
80
81
|
b_subtree = subtree(nodes, b)
|
|
81
82
|
|
|
82
83
|
b_subtree_duplicated = b_subtree.join(vars, how="cross", suffix="_major")
|
|
83
|
-
rest_of_nodes =
|
|
84
|
-
|
|
84
|
+
rest_of_nodes = (
|
|
85
|
+
nodes.lazy()
|
|
86
|
+
.join(b_subtree, on="id", how="anti")
|
|
87
|
+
.with_columns(arg=pl.col("arg").replace(redex, a))
|
|
85
88
|
)
|
|
86
89
|
|
|
87
90
|
new_nodes = (
|
|
88
91
|
pl.concat(
|
|
89
92
|
[b_subtree_duplicated, rest_of_nodes],
|
|
90
|
-
how="
|
|
93
|
+
how="diagonal",
|
|
91
94
|
)
|
|
92
95
|
.join(vars, left_on="id", right_on="id", how="anti")
|
|
93
96
|
.join(vars, left_on="arg", right_on="id", how="left", suffix="_arg")
|
|
94
97
|
.join(vars, left_on="ref", right_on="id", how="left", suffix="_ref")
|
|
95
98
|
.filter(
|
|
96
|
-
~pl.col("id").
|
|
99
|
+
~(pl.col("id").eq(redex) | pl.col("id").eq(lamb)),
|
|
97
100
|
)
|
|
98
101
|
.select(
|
|
99
102
|
bid=_generate_bi_identifier("id_major", "id"),
|
|
100
103
|
bid_ref=_generate_bi_identifier("id_major", "ref"),
|
|
101
104
|
bid_ref_fallback=pl.struct(major="ref", minor="ref"),
|
|
102
105
|
bid_arg=_generate_bi_identifier(
|
|
103
|
-
|
|
106
|
+
# TODO: document and simplify to avoid "minor_replacement"
|
|
107
|
+
"id_major",
|
|
108
|
+
"arg",
|
|
109
|
+
minor_replacement=pl.when("replaced_arg").then(b),
|
|
104
110
|
),
|
|
105
111
|
)
|
|
106
112
|
.sort("bid")
|
|
107
113
|
.with_row_index("id")
|
|
108
|
-
)
|
|
114
|
+
).cache()
|
|
109
115
|
|
|
110
116
|
return (
|
|
111
117
|
new_nodes.join(
|
|
112
118
|
new_nodes.select(bid_ref="bid", ref="id"),
|
|
113
119
|
on="bid_ref",
|
|
114
120
|
how="left",
|
|
121
|
+
maintain_order="left",
|
|
115
122
|
)
|
|
116
123
|
.join(
|
|
117
124
|
new_nodes.select(bid_ref_fallback="bid", ref_fallback="id"),
|
|
118
125
|
on="bid_ref_fallback",
|
|
119
126
|
how="left",
|
|
127
|
+
maintain_order="left",
|
|
120
128
|
)
|
|
121
129
|
.join(
|
|
122
130
|
new_nodes.select(bid_arg="bid", arg="id"),
|
|
123
131
|
on="bid_arg",
|
|
124
132
|
how="left",
|
|
133
|
+
maintain_order="left",
|
|
125
134
|
)
|
|
126
135
|
.select("id", ref=pl.coalesce("ref", "ref_fallback"), arg="arg", bid="bid")
|
|
127
|
-
|
|
128
|
-
)
|
|
136
|
+
).collect()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|