funstruct 0.1.0__tar.gz → 0.1.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.
- {funstruct-0.1.0 → funstruct-0.1.2}/PKG-INFO +4 -2
- funstruct-0.1.2/funstruct/__init__.py +0 -0
- {funstruct-0.1.0 → funstruct-0.1.2}/pyproject.toml +5 -2
- funstruct-0.1.0/funstruct/__init__.py +0 -2
- funstruct-0.1.0/funstruct/_cons2.py +0 -17
- funstruct-0.1.0/funstruct/yo.py +0 -223
- {funstruct-0.1.0 → funstruct-0.1.2}/LICENSE +0 -0
- {funstruct-0.1.0 → funstruct-0.1.2}/README.md +0 -0
- /funstruct-0.1.0/funstruct/_cons.py → /funstruct-0.1.2/funstruct/cons.py +0 -0
- /funstruct-0.1.0/funstruct/_frozendict.py → /funstruct-0.1.2/funstruct/frozendict.py +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: funstruct
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: fun & functional structures
|
|
5
|
+
Home-page: https://github.com/veyga/funstruct
|
|
5
6
|
License: MIT
|
|
6
|
-
Keywords: functional,immutable,fp
|
|
7
|
+
Keywords: functional,immutable,fp,data structures,cons
|
|
7
8
|
Author: Andrew Stefanich
|
|
8
9
|
Author-email: andrewstefanich@gmail.com
|
|
9
10
|
Requires-Python: >=3.12,<4.0
|
|
@@ -12,6 +13,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
14
|
Requires-Dist: pytest-parametrization (>=2022.2.1,<2023.0.0)
|
|
14
15
|
Requires-Dist: returns (>=0.23.0,<0.24.0)
|
|
16
|
+
Project-URL: Repository, https://github.com/veyga/funstruct
|
|
15
17
|
Description-Content-Type: text/markdown
|
|
16
18
|
|
|
17
19
|
# funstruct
|
|
File without changes
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "funstruct"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.2"
|
|
4
4
|
description = "fun & functional structures"
|
|
5
5
|
authors = ["Andrew Stefanich <andrewstefanich@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
7
7
|
readme = "README.md"
|
|
8
|
-
|
|
8
|
+
homepage = "https://github.com/veyga/funstruct"
|
|
9
|
+
repository = "https://github.com/veyga/funstruct"
|
|
10
|
+
keywords = ["functional", "immutable", "fp", "data structures", "cons"]
|
|
9
11
|
|
|
10
12
|
[tool.poetry.dependencies]
|
|
11
13
|
python = "^3.12"
|
|
@@ -18,6 +20,7 @@ pytest = "^8.3.2"
|
|
|
18
20
|
debugpy = "^1.8.2"
|
|
19
21
|
black = "^24.4.2"
|
|
20
22
|
pre-commit = "^3.7.1"
|
|
23
|
+
sphinx = "^7.4.7"
|
|
21
24
|
|
|
22
25
|
[build-system]
|
|
23
26
|
requires = ["poetry-core"]
|
funstruct-0.1.0/funstruct/yo.py
DELETED
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
A Lisp/ML/Scala style singly linked list ("cons list")
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from abc import abstractmethod, ABC
|
|
6
|
-
from dataclasses import dataclass, field
|
|
7
|
-
from typing import Callable, Iterable, Tuple
|
|
8
|
-
from typing import TypeVar
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
A = TypeVar("A")
|
|
12
|
-
|
|
13
|
-
type _CList = "CList[A]"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class CList[A](ABC):
|
|
17
|
-
|
|
18
|
-
@abstractmethod
|
|
19
|
-
def append(self, other: _CList) -> _CList: ...
|
|
20
|
-
|
|
21
|
-
@abstractmethod
|
|
22
|
-
def fold_right[B](self, acc: B, f: Callable[[A, B], B]) -> B: ...
|
|
23
|
-
|
|
24
|
-
@abstractmethod
|
|
25
|
-
def fold_left[B](self, acc: B, f: Callable[[B, A], B]) -> B: ...
|
|
26
|
-
|
|
27
|
-
@abstractmethod
|
|
28
|
-
def drop(self, n: int) -> _CList: ...
|
|
29
|
-
|
|
30
|
-
@abstractmethod
|
|
31
|
-
def drop_while(self, f: Callable[[A], bool]) -> _CList: ...
|
|
32
|
-
|
|
33
|
-
@abstractmethod
|
|
34
|
-
def take(self, n: int) -> _CList: ...
|
|
35
|
-
|
|
36
|
-
@abstractmethod
|
|
37
|
-
def take_while(self, f: Callable[[A], bool]) -> _CList: ...
|
|
38
|
-
|
|
39
|
-
@abstractmethod
|
|
40
|
-
def split_at(self, i: int) -> Tuple[_CList, _CList]: ...
|
|
41
|
-
|
|
42
|
-
def partition(self, f: Callable[[A], bool]) -> Tuple[_CList, _CList]:
|
|
43
|
-
accum = lambda a, x: (a << x[0], x[1]) if f(a) else (x[0], a << x[1])
|
|
44
|
-
return self.fold_right((Nil(), Nil()), accum)
|
|
45
|
-
|
|
46
|
-
def length(self) -> int:
|
|
47
|
-
return self.fold_right(0, lambda _, acc: acc + 1)
|
|
48
|
-
|
|
49
|
-
def prepend(self, new_head: A) -> _CList:
|
|
50
|
-
return Cons(new_head, self)
|
|
51
|
-
|
|
52
|
-
def reversed(self) -> _CList:
|
|
53
|
-
return self.fold_left(Nil(), lambda acc, h: Cons(h, acc))
|
|
54
|
-
|
|
55
|
-
def map[B](self, f: Callable[[A], B]) -> "CList[B]":
|
|
56
|
-
return self.fold_right(Nil(), lambda a, acc: Cons(f(a), acc))
|
|
57
|
-
|
|
58
|
-
def filter[A](self, f: Callable[[A], bool]) -> _CList:
|
|
59
|
-
return self.fold_right(Nil(), lambda a, acc: Cons(a, acc) if f(a) else acc)
|
|
60
|
-
|
|
61
|
-
def flatten(self) -> _CList:
|
|
62
|
-
return CList.flatten_(self)
|
|
63
|
-
|
|
64
|
-
def flat_map[B](self, f: Callable[[A], "CList[B]"]) -> "CList[B]":
|
|
65
|
-
return self.map(f).flatten()
|
|
66
|
-
|
|
67
|
-
def bind[B](self, f: Callable[[A], "CList[B]"]) -> "CList[B]":
|
|
68
|
-
return self.map(f).flatten()
|
|
69
|
-
|
|
70
|
-
def sorted(self, cmp: Callable[[A, A], int]) -> _CList:
|
|
71
|
-
def merge(left: _CList, right: _CList) -> _CList:
|
|
72
|
-
match left, right:
|
|
73
|
-
case Nil(), r:
|
|
74
|
-
return r
|
|
75
|
-
case l, Nil():
|
|
76
|
-
return l
|
|
77
|
-
case Cons(lh, lt), Cons(rh, rt):
|
|
78
|
-
if cmp(lh, rh) <= 0:
|
|
79
|
-
return lh << merge(lt, right)
|
|
80
|
-
return rh << merge(left, rt)
|
|
81
|
-
case _:
|
|
82
|
-
return Nil()
|
|
83
|
-
|
|
84
|
-
length = len(self)
|
|
85
|
-
if length <= 1:
|
|
86
|
-
return self
|
|
87
|
-
left, right = self.split_at(length // 2)
|
|
88
|
-
return merge(left.sorted(cmp), right.sorted(cmp))
|
|
89
|
-
|
|
90
|
-
@staticmethod
|
|
91
|
-
def flatten_(lst: "CList[CList[A]]") -> _CList:
|
|
92
|
-
def concat(left, right):
|
|
93
|
-
match left:
|
|
94
|
-
case Nil():
|
|
95
|
-
return right
|
|
96
|
-
case Cons(h, t):
|
|
97
|
-
return Cons(h, concat(t, right))
|
|
98
|
-
|
|
99
|
-
def flatten(lst: "CList[CList[A]]") -> "CList[A]":
|
|
100
|
-
match lst:
|
|
101
|
-
case Nil():
|
|
102
|
-
return Nil()
|
|
103
|
-
case Cons(h, t):
|
|
104
|
-
match h:
|
|
105
|
-
case Cons(_, _):
|
|
106
|
-
return concat(flatten(h), flatten(t))
|
|
107
|
-
case _:
|
|
108
|
-
return Cons(h, flatten(t))
|
|
109
|
-
|
|
110
|
-
return flatten(lst)
|
|
111
|
-
|
|
112
|
-
@staticmethod
|
|
113
|
-
def cons(a: A) -> _CList:
|
|
114
|
-
return Cons(a)
|
|
115
|
-
|
|
116
|
-
@staticmethod
|
|
117
|
-
def empty() -> _CList:
|
|
118
|
-
return Nil()
|
|
119
|
-
|
|
120
|
-
@staticmethod
|
|
121
|
-
def new(*xs: A) -> _CList:
|
|
122
|
-
return Cons(xs[0], CList.new(*xs[1:])) if xs else Nil()
|
|
123
|
-
|
|
124
|
-
@staticmethod
|
|
125
|
-
def from_iterable[A](iterable: Iterable[A]) -> _CList:
|
|
126
|
-
return CList.new(*iterable)
|
|
127
|
-
|
|
128
|
-
def __rlshift__(self, other) -> _CList:
|
|
129
|
-
return self.prepend(other)
|
|
130
|
-
|
|
131
|
-
def __add__(self, other) -> _CList:
|
|
132
|
-
return self.append(other)
|
|
133
|
-
|
|
134
|
-
def __len__(self) -> int:
|
|
135
|
-
return self.fold_right(0, lambda _, acc: acc + 1)
|
|
136
|
-
|
|
137
|
-
def __iter__(self):
|
|
138
|
-
current = self
|
|
139
|
-
while isinstance(current, Cons):
|
|
140
|
-
yield current.head
|
|
141
|
-
current = current.tail
|
|
142
|
-
|
|
143
|
-
def __eq__(self, other) -> bool:
|
|
144
|
-
match self, other:
|
|
145
|
-
case Cons(sh, st), Cons(oh, ot):
|
|
146
|
-
return sh == oh and st == ot
|
|
147
|
-
case Nil(), Nil():
|
|
148
|
-
return True
|
|
149
|
-
case _:
|
|
150
|
-
return False
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
class Nil(CList):
|
|
154
|
-
|
|
155
|
-
_instance = None
|
|
156
|
-
|
|
157
|
-
def __new__(cls):
|
|
158
|
-
if cls._instance is None:
|
|
159
|
-
cls._instance = super(Nil, cls).__new__(cls)
|
|
160
|
-
return cls._instance
|
|
161
|
-
|
|
162
|
-
def __repr__(self):
|
|
163
|
-
return "Nil()"
|
|
164
|
-
|
|
165
|
-
def append(self, other: _CList) -> _CList:
|
|
166
|
-
return other
|
|
167
|
-
|
|
168
|
-
def fold_right[A, B](self, acc: B, f: Callable[[A, B], B]) -> B:
|
|
169
|
-
return acc
|
|
170
|
-
|
|
171
|
-
def fold_left[A, B](self, acc: B, f: Callable[[B, A], B]) -> B:
|
|
172
|
-
return acc
|
|
173
|
-
|
|
174
|
-
def drop(self, n: int) -> _CList:
|
|
175
|
-
return self
|
|
176
|
-
|
|
177
|
-
def drop_while[A](self, f: Callable[[A], bool]) -> _CList:
|
|
178
|
-
return self
|
|
179
|
-
|
|
180
|
-
def take(self, n: int) -> _CList:
|
|
181
|
-
return self
|
|
182
|
-
|
|
183
|
-
def take_while[A](self, f: Callable[[A], bool]) -> _CList:
|
|
184
|
-
return self
|
|
185
|
-
|
|
186
|
-
def split_at(self, i: int) -> Tuple[_CList, _CList]:
|
|
187
|
-
return self, self
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
@dataclass(frozen=True)
|
|
191
|
-
class Cons[A](CList[A]):
|
|
192
|
-
head: A
|
|
193
|
-
tail: CList[A] = field(default_factory=Nil)
|
|
194
|
-
|
|
195
|
-
def __repr__(self):
|
|
196
|
-
match self.tail:
|
|
197
|
-
case Nil():
|
|
198
|
-
return f"Cons({self.head})"
|
|
199
|
-
return f"Cons({self.head}, {self.tail})"
|
|
200
|
-
|
|
201
|
-
def append(self, other: _CList) -> _CList:
|
|
202
|
-
return Cons(self.head, self.tail.append(other))
|
|
203
|
-
|
|
204
|
-
def fold_right[B](self, acc: B, f: Callable[[A, B], B]) -> B:
|
|
205
|
-
return f(self.head, self.tail.fold_right(acc, f))
|
|
206
|
-
|
|
207
|
-
def fold_left[B](self, acc: B, f: Callable[[B, A], B]) -> B:
|
|
208
|
-
return self.tail.fold_left(f(acc, self.head), f)
|
|
209
|
-
|
|
210
|
-
def drop(self, n: int) -> _CList:
|
|
211
|
-
return self if n <= 0 else self.tail.drop(n - 1)
|
|
212
|
-
|
|
213
|
-
def drop_while(self, f: Callable[[A], bool]) -> _CList:
|
|
214
|
-
return self if not f(self.head) else self.tail.drop_while(f)
|
|
215
|
-
|
|
216
|
-
def take(self, n: int) -> _CList:
|
|
217
|
-
return Cons(self.head) if n <= 1 else self.head << self.tail.take(n - 1)
|
|
218
|
-
|
|
219
|
-
def take_while(self, f: Callable[[A], bool]) -> _CList:
|
|
220
|
-
return self.head << self.tail.take_while(f) if f(self.head) else Nil()
|
|
221
|
-
|
|
222
|
-
def split_at(self, i: int) -> Tuple[_CList, _CList]:
|
|
223
|
-
return self.take(i), self.drop(i)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|