Skip to content

Instantly share code, notes, and snippets.

@LeeeeT
Last active February 7, 2024 19:25
Show Gist options
  • Save LeeeeT/8e44c2f81b69665f43cf02481fdabe8a to your computer and use it in GitHub Desktop.
Save LeeeeT/8e44c2f81b69665f43cf02481fdabe8a to your computer and use it in GitHub Desktop.
Order
from collections.abc import Callable
from dataclasses import dataclass
from typing import Concatenate
@dataclass(frozen=True)
class Partial1[First, **Rest, Result]:
function: Callable[Concatenate[First, Rest], Result]
first: First
def __call__(self, *args: Rest.args, **kwargs: Rest.kwargs) -> Result:
return self.function(self.first, *args, **kwargs)
@dataclass(frozen=True)
class Partial2[First, Second, **Rest, Result]:
function: Callable[Concatenate[First, Second, Rest], Result]
first: First
second: Second
def __call__(self, *args: Rest.args, **kwargs: Rest.kwargs) -> Result:
return self.function(self.first, self.second, *args, **kwargs)
@dataclass(frozen=True)
class Curry1[First, **Rest, Result]:
function: Callable[Concatenate[First, Rest], Result]
def __call__(self, first: First) -> Callable[Rest, Result]:
return Partial1(self.function, first)
@dataclass(frozen=True)
class Curry2[First, Second, **Rest, Result]:
function: Callable[Concatenate[First, Second, Rest], Result]
def __call__(self, first: First, second: Second) -> Callable[Rest, Result]:
return Partial2(self.function, first, second)
@dataclass(frozen=True)
class Uncurry1[First, **Rest, Result]:
function: Callable[[First], Callable[Rest, Result]]
def __call__(self, first: First, *args: Rest.args, **kwargs: Rest.kwargs) -> Result:
return self.function(first)(*args, **kwargs)
@dataclass(frozen=True)
class Uncurry2[First, Second, **Rest, Result]:
function: Callable[[First], Callable[[Second], Callable[Rest, Result]]]
def __call__(self, first: First, second: Second, *args: Rest.args, **kwargs: Rest.kwargs) -> Result:
return self.function(first)(second)(*args, **kwargs)
type Predicate[Value] = Callable[[Value], bool]
def predicate_both[Value](second: Predicate[Value], first: Predicate[Value], value: Value) -> bool:
return first(value) and second(value)
def make_predicate_both[Value](second: Predicate[Value], first: Predicate[Value]) -> Predicate[Value]:
return Partial2(predicate_both, second, first)
def predicate_either[Value](second: Predicate[Value], first: Predicate[Value], value: Value) -> bool:
return first(value) or second(value)
def make_predicate_either[Value](second: Predicate[Value], first: Predicate[Value]) -> Predicate[Value]:
return Partial2(predicate_either, second, first)
def predicate_not[Value](predicate: Predicate[Value], value: Value) -> bool:
return not predicate(value)
def make_predicate_not[Value](predicate: Predicate[Value]) -> Predicate[Value]:
return Partial1(predicate_not, predicate)
class OrderingLess:
pass
class OrderingEqual:
pass
class OrderingGreater:
pass
type Ordering = OrderingLess | OrderingEqual | OrderingGreater
def ordering_equal(a: Ordering, b: Ordering) -> bool:
match a, b:
case OrderingLess(), OrderingLess():
return True
case OrderingEqual(), OrderingEqual():
return True
case OrderingGreater(), OrderingGreater():
return True
case _:
return False
def make_ordering_equal(a: Ordering) -> Predicate[Ordering]:
return Partial1(ordering_equal, a)
is_ordering_less = make_ordering_equal(OrderingLess())
is_ordering_equal = make_ordering_equal(OrderingEqual())
is_ordering_greater = make_ordering_equal(OrderingGreater())
is_ordering_less_or_equal = make_predicate_either(is_ordering_less, is_ordering_equal)
is_ordering_greater_or_equal = make_predicate_either(is_ordering_greater, is_ordering_equal)
is_ordering_different = make_predicate_not(is_ordering_equal)
type Order[Value] = Callable[[Value, Value], Ordering]
def order_predicate[Value](predicate: Predicate[Ordering], order: Order[Value], a: Value, b: Value) -> bool:
return predicate(order(a, b))
def make_order_predicate[Value](predicate: Predicate[Ordering], order: Order[Value]) -> Callable[[Value, Value], bool]:
return Partial2(order_predicate, predicate, order)
def make_make_order_predicate[Value](predicate: Predicate[Ordering]) -> Callable[[Order[Value]], Callable[[Value, Value], bool]]:
return Partial1(make_order_predicate, predicate)
make_less = make_make_order_predicate(is_ordering_less)
make_equal = make_make_order_predicate(is_ordering_equal)
make_greater = make_make_order_predicate(is_ordering_greater)
make_less_or_equal = make_make_order_predicate(is_ordering_less_or_equal)
make_greater_or_equal = make_make_order_predicate(is_ordering_greater_or_equal)
make_different = make_make_order_predicate(is_ordering_different)
def make_range[Value](make_lower_bound_predicate: Callable[[Value], Predicate[Value]], make_upper_bound_predicate: Callable[[Value], Predicate[Value]], minimum: Value, maximum: Value) -> Predicate[Value]:
return make_predicate_both(make_lower_bound_predicate(minimum), make_upper_bound_predicate(maximum))
def make_make_range[Value](make_lower_bound_predicate: Callable[[Value], Predicate[Value]], make_upper_bound_predicate: Callable[[Value], Predicate[Value]]) -> Callable[[Value, Value], Predicate[Value]]:
return Partial2(make_range, make_lower_bound_predicate, make_upper_bound_predicate)
def int_order(a: int, b: int) -> Ordering:
if a > b:
return OrderingLess()
if a < b:
return OrderingGreater()
return OrderingEqual()
int_less = make_less(int_order)
def make_int_less(compared: int) -> Predicate[int]:
return Partial1(int_less, compared)
int_equal = make_equal(int_order)
def make_int_equal(compared: int) -> Predicate[int]:
return Partial1(int_equal, compared)
int_greater = make_greater(int_order)
def make_int_greater(compared: int) -> Predicate[int]:
return Partial1(int_greater, compared)
int_less_or_equal = make_less_or_equal(int_order)
def make_int_less_or_equal(compared: int) -> Predicate[int]:
return Partial1(int_less_or_equal, compared)
int_greater_or_equal = make_greater_or_equal(int_order)
def make_int_greater_or_equal(compared: int) -> Predicate[int]:
return Partial1(int_greater_or_equal, compared)
int_different = make_different(int_order)
def make_int_different(compared: int) -> Predicate[int]:
return Partial1(int_different, compared)
int_inclusive_inclusive = make_make_range(make_int_greater_or_equal, make_int_less_or_equal)
int_inclusive_exclusive = make_make_range(make_int_greater_or_equal, make_int_less)
int_exclusive_inclusive = make_make_range(make_int_greater, make_int_less_or_equal)
int_exclusive_exclusive = make_make_range(make_int_greater, make_int_less)
between_1_and_10 = int_inclusive_inclusive(1, 10)
match between_1_and_10(int(input())):
case True:
print("Yay!")
case False:
print("Oh..")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment