Skip to content

Commit 77976c4

Browse files
authored
39 flatten Values for associative operators (#65)
* Make combining constants return a constant * Make encapsulating Values with associative functions flatten to single Value
1 parent cc39dd1 commit 77976c4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2262
-961
lines changed

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ spellbind is a reactive programming library that lets you create Variables that
1010
## Installation
1111

1212
```bash
13-
git clone https://github.com/FancyNeuron/spellbind.git
14-
cd spellbind
15-
pip install -e .
13+
pip install spellbind
1614
```
1715

1816
## Quick Start

src/spellbind/bool_values.py

Lines changed: 86 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
import operator
44
from abc import ABC
5-
from typing import TypeVar, Generic, overload, TYPE_CHECKING, TypeAlias
6-
from spellbind.values import Value, OneToOneValue, Constant, SimpleVariable, TwoToOneValue, SelectValue
5+
from typing import TypeVar, Generic, overload, TYPE_CHECKING, TypeAlias, Callable, Iterable
6+
7+
from spellbind.values import Value, OneToOneValue, Constant, SimpleVariable, TwoToOneValue, \
8+
ManyToSameValue, ThreeToOneValue
79

810
if TYPE_CHECKING:
911
from spellbind.float_values import FloatValue # pragma: no cover
@@ -16,34 +18,45 @@
1618
BoolValueLike: TypeAlias = 'BoolValue | bool'
1719

1820
_S = TypeVar('_S')
21+
_T = TypeVar('_T')
22+
_U = TypeVar('_U')
23+
_V = TypeVar('_V')
24+
1925

2026
BoolLike = bool | Value[bool]
2127
IntLike = int | Value[int]
2228
FloatLike = float | Value[float]
2329
StrLike = str | Value[str]
2430

2531

32+
def _select_function(b: bool, t: _S, f: _S) -> _S:
33+
if b:
34+
return t
35+
return f
36+
37+
2638
class BoolValue(Value[bool], ABC):
39+
@property
2740
def logical_not(self) -> BoolValue:
2841
return NotBoolValue(self)
2942

3043
def __and__(self, other: BoolLike) -> BoolValue:
31-
return AndBoolValues(self, other)
44+
return BoolValue.derive_from_many(all, self, other, is_associative=True)
3245

3346
def __rand__(self, other: bool) -> BoolValue:
34-
return AndBoolValues(other, self)
47+
return BoolValue.derive_from_many(all, other, self, is_associative=True)
3548

3649
def __or__(self, other: BoolLike) -> BoolValue:
37-
return OrBoolValues(self, other)
50+
return BoolValue.derive_from_many(any, self, other, is_associative=True)
3851

3952
def __ror__(self, other: bool) -> BoolValue:
40-
return OrBoolValues(other, self)
53+
return BoolValue.derive_from_many(any, other, self, is_associative=True)
4154

4255
def __xor__(self, other: BoolLike) -> BoolValue:
43-
return XorBoolValues(self, other)
56+
return BoolValue.derive_from_two(operator.xor, self, other)
4457

4558
def __rxor__(self, other: bool) -> BoolValue:
46-
return XorBoolValues(other, self)
59+
return BoolValue.derive_from_two(operator.xor, other, self)
4760

4861
@overload
4962
def select(self, if_true: IntValueLike, if_false: IntValueLike) -> IntValue: ...
@@ -61,20 +74,50 @@ def select(self, if_true: BoolValue, if_false: BoolValue) -> BoolValue: ...
6174
def select(self, if_true: Value[_S] | _S, if_false: Value[_S] | _S) -> Value[_S]: ...
6275

6376
def select(self, if_true, if_false):
64-
from spellbind.float_values import FloatValue, SelectFloatValue
65-
from spellbind.int_values import IntValue, SelectIntValue
66-
from spellbind.str_values import StrValue, SelectStrValue
77+
from spellbind.float_values import FloatValue
78+
from spellbind.int_values import IntValue
79+
from spellbind.str_values import StrValue
6780

6881
if isinstance(if_true, (FloatValue, float)) and isinstance(if_false, (FloatValue, float)):
69-
return SelectFloatValue(self, if_true, if_false)
82+
return FloatValue.derive_from_three(_select_function, self, if_true, if_false)
7083
elif isinstance(if_true, (StrValue, str)) and isinstance(if_false, (StrValue, str)):
71-
return SelectStrValue(self, if_true, if_false)
84+
return StrValue.derive_from_three(_select_function, self, if_true, if_false)
7285
elif isinstance(if_true, (BoolValue, bool)) and isinstance(if_false, (BoolValue, bool)):
73-
return SelectBoolValue(self, if_true, if_false)
86+
return BoolValue.derive_from_three(_select_function, self, if_true, if_false)
7487
elif isinstance(if_true, (IntValue, int)) and isinstance(if_false, (IntValue, int)):
75-
return SelectIntValue(self, if_true, if_false)
88+
return IntValue.derive_from_three(_select_function, self, if_true, if_false)
7689
else:
77-
return SelectValue(self, if_true, if_false)
90+
return Value.derive_three_value(_select_function, self, if_true, if_false)
91+
92+
@classmethod
93+
def derive_from_two(cls, transformer: Callable[[bool, bool], bool],
94+
first: BoolLike, second: BoolLike) -> BoolValue:
95+
return Value.derive_from_two_with_factory(
96+
transformer,
97+
first, second,
98+
create_value=TwoToBoolValue.create,
99+
create_constant=BoolConstant.of,
100+
)
101+
102+
@classmethod
103+
def derive_from_three(cls, transformer: Callable[[_S, _T, _U], bool],
104+
first: _S | Value[_S], second: _T | Value[_T], third: _U | Value[_U]) -> BoolValue:
105+
return Value.derive_from_three_with_factory(
106+
transformer,
107+
first, second, third,
108+
create_value=ThreeToBoolValue.create,
109+
create_constant=BoolConstant.of,
110+
)
111+
112+
@classmethod
113+
def derive_from_many(cls, transformer: Callable[[Iterable[bool]], bool], *values: BoolLike, is_associative: bool = False) -> BoolValue:
114+
return Value.derive_from_many_with_factory(
115+
transformer,
116+
*values,
117+
create_value=ManyBoolToBoolValue.create,
118+
create_constant=BoolConstant.of,
119+
is_associative=is_associative,
120+
)
78121

79122

80123
class OneToBoolValue(OneToOneValue[_S, bool], BoolValue, Generic[_S]):
@@ -86,32 +129,44 @@ def __init__(self, value: Value[bool]):
86129
super().__init__(operator.not_, value)
87130

88131

89-
class AndBoolValues(TwoToOneValue[bool, bool, bool], BoolValue):
90-
def __init__(self, left: BoolLike, right: BoolLike):
91-
super().__init__(operator.and_, left, right)
132+
class ManyBoolToBoolValue(ManyToSameValue[bool], BoolValue):
133+
@staticmethod
134+
def create(transformer: Callable[[Iterable[bool]], bool], values: Iterable[BoolLike]) -> BoolValue:
135+
return ManyBoolToBoolValue(transformer, *values)
92136

93137

94-
class OrBoolValues(TwoToOneValue[bool, bool, bool], BoolValue):
95-
def __init__(self, left: BoolLike, right: BoolLike):
96-
super().__init__(operator.or_, left, right)
138+
class BoolConstant(BoolValue, Constant[bool]):
139+
@classmethod
140+
def of(cls, value: bool) -> BoolConstant:
141+
if value:
142+
return TRUE
143+
return FALSE
97144

145+
@property
146+
def logical_not(self) -> BoolConstant:
147+
return BoolConstant.of(not self.value)
98148

99-
class XorBoolValues(TwoToOneValue[bool, bool, bool], BoolValue):
100-
def __init__(self, left: BoolLike, right: BoolLike):
101-
super().__init__(operator.xor, left, right)
149+
@property
150+
def constant_value_or_raise(self) -> bool:
151+
return self.value
102152

103153

104-
class BoolConstant(BoolValue, Constant[bool]):
154+
class BoolVariable(SimpleVariable[bool], BoolValue):
105155
pass
106156

107157

108-
class BoolVariable(SimpleVariable[bool], BoolValue):
109-
pass
158+
class ThreeToBoolValue(ThreeToOneValue[_S, _T, _U, bool], BoolValue):
159+
@staticmethod
160+
def create(transformer: Callable[[_S, _T, _U], bool],
161+
first: _S | Value[_S], second: _T | Value[_T], third: _U | Value[_U]) -> BoolValue:
162+
return ThreeToBoolValue(transformer, first, second, third)
110163

111164

112-
class SelectBoolValue(SelectValue[bool], BoolValue):
113-
def __init__(self, condition: BoolLike, if_true: BoolLike, if_false: BoolLike):
114-
super().__init__(condition, if_true, if_false)
165+
class TwoToBoolValue(TwoToOneValue[_S, _T, bool], BoolValue):
166+
@staticmethod
167+
def create(transformer: Callable[[_S, _T], bool],
168+
first: _S | Value[_S], second: _T | Value[_T]) -> BoolValue:
169+
return TwoToBoolValue(transformer, first, second)
115170

116171

117172
TRUE = BoolConstant(True)

0 commit comments

Comments
 (0)