Some funky lil funktions
This commit is contained in:
commit
adddc0704d
155
emis_funky_funktions.py
Normal file
155
emis_funky_funktions.py
Normal file
|
@ -0,0 +1,155 @@
|
|||
from dataclasses import dataclass
|
||||
from functools import partial, reduce, wraps
|
||||
from typing import Any, Callable, Generic, ParamSpec, Sequence, Tuple, TypeVar
|
||||
|
||||
A = TypeVar('A')
|
||||
B = TypeVar('B')
|
||||
C = TypeVar('C')
|
||||
D = TypeVar('D')
|
||||
P = ParamSpec('P')
|
||||
|
||||
|
||||
# Compose
|
||||
def c(f2: Callable[[B], C], f1: Callable[[A], B]) -> Callable[[A], C]:
|
||||
return lambda a: f2(f1(a))
|
||||
|
||||
# Flip: (A -> B -> C) -> B -> A -> C
|
||||
def flip(f: Callable[[A],Callable[[B], C]]) -> Callable[[B], Callable[[A], C]]:
|
||||
return wraps(f)(lambda b: wraps(f)(lambda a: f(a)(b)))
|
||||
|
||||
# Partial Appliaction shorthand
|
||||
p = partial
|
||||
|
||||
# Two and three-argument currying
|
||||
# Defining these pointfree fucks up the types btw
|
||||
def cur2(f: Callable[[A, B], C]) -> Callable[[A], Callable[[B], C]]:
|
||||
return p(p, f) #type:ignore
|
||||
def cur3(f: Callable[[A, B, C], D]) -> Callable[[A], Callable[[B], Callable[[C], D]]]:
|
||||
return p(p, p, f) #type:ignore
|
||||
|
||||
# Curried versions of map & filter with stricter types
|
||||
def p_map(f: Callable[[A], B]) -> Callable[[Sequence[A]], Sequence[B]]:
|
||||
return partial(map, f) #type: ignore
|
||||
|
||||
def p_filter(f: Callable[[A], bool]) -> Callable[[Sequence[A]], Sequence[A]]:
|
||||
return partial(filter,f) #type: ignore
|
||||
|
||||
# Normal Accessors
|
||||
@cur2
|
||||
def indx(i: int, s: Sequence[A]) -> A:
|
||||
return s[i]
|
||||
fst = indx(0)
|
||||
snd = indx(1)
|
||||
|
||||
# Semantic Editor Combinators
|
||||
class SemEdComb:
|
||||
class Inner():
|
||||
def __init__(self, f: Callable, name: str):
|
||||
self.f = f
|
||||
self.name = name
|
||||
def and_then(self, other: 'SemEdComb.Inner') -> 'SemEdComb.Inner':
|
||||
return SemEdComb.Inner(c(other.f, self.f), self.name + ' and ' + other.name)
|
||||
def __repr__(self) -> str:
|
||||
return f"SemEdComb*({self.name})"
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.f(*args, **kwargs)
|
||||
|
||||
def __init__(self, f: Callable[[Callable],Callable], name: str):
|
||||
self.f = f
|
||||
self.name = name
|
||||
|
||||
def _c(self, next_f: Callable[[Callable], Callable], next_fname: str) -> 'SemEdComb':
|
||||
return SemEdComb(c(self.f, next_f), self.name + next_fname)
|
||||
|
||||
RESULT = cur2(c)
|
||||
ARG = flip(RESULT)
|
||||
ALL = p_map
|
||||
|
||||
@cur3
|
||||
@staticmethod
|
||||
def INDEX(i, f, arr):
|
||||
arr[i] = f(arr[i])
|
||||
return arr
|
||||
|
||||
@cur3
|
||||
@staticmethod
|
||||
def INDEX_TUP(i: int, f: Callable[[Any], Any], tup: Tuple) -> Tuple:
|
||||
l = list(tup)
|
||||
l[i] = f(l[i])
|
||||
return (*l,)
|
||||
|
||||
@cur2
|
||||
@staticmethod
|
||||
def FIRST(f: Callable[[A], C], tup: Tuple[A, B]) -> Tuple[C, B]:
|
||||
return (f(tup[0]), tup[1])
|
||||
|
||||
@cur2
|
||||
@staticmethod
|
||||
def SECOND(f: Callable[[B], C], tup: Tuple[A, B]) -> Tuple[A, C]:
|
||||
return (tup[0], f(tup[1]))
|
||||
|
||||
@property
|
||||
def result(self) -> 'SemEdComb':
|
||||
return self._c(SemEdComb.RESULT, '.result')
|
||||
|
||||
@property
|
||||
def arg(self) -> 'SemEdComb':
|
||||
return self._c(SemEdComb.ARG, '.arg')
|
||||
|
||||
@property
|
||||
def all(self) -> 'SemEdComb':
|
||||
return self._c(SemEdComb.ALL, '.all')
|
||||
|
||||
def index(self, i) -> 'SemEdComb':
|
||||
return self._c(SemEdComb.INDEX(i), f'.index({i})')
|
||||
|
||||
def index_tup(self, i) -> 'SemEdComb':
|
||||
return self._c(SemEdComb.INDEX_TUP(i), f'.index_tup({i})')
|
||||
|
||||
@property
|
||||
def first(self) -> 'SemEdComb':
|
||||
return self._c(SemEdComb.FIRST, f'.first')
|
||||
|
||||
@property
|
||||
def second(self) -> 'SemEdComb':
|
||||
return self._c(SemEdComb.SECOND, f'.second')
|
||||
|
||||
def __repr__(self):
|
||||
return f"SemEdComb({self.name})"
|
||||
|
||||
def pmap(self, mapper):
|
||||
return SemEdComb.Inner(self.f(mapper), self.name)
|
||||
|
||||
def map(self, mapper, thing_to_map) -> Callable:
|
||||
return self.pmap(mapper)(thing_to_map)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.f(*args, **kwargs)
|
||||
|
||||
result = SemEdComb(SemEdComb.RESULT, 'result')
|
||||
arg = SemEdComb(SemEdComb.ARG, 'arg')
|
||||
index = lambda i: SemEdComb(SemEdComb.INDEX(i), f'index({i})')
|
||||
index_tup = lambda i: SemEdComb(SemEdComb.INDEX_TUP(i), f'index_tup({i})')
|
||||
first = SemEdComb(SemEdComb.FIRST, 'first')
|
||||
second = SemEdComb(SemEdComb.SECOND, 'second')
|
||||
_all = SemEdComb(SemEdComb.ALL, 'all')
|
||||
|
||||
# Tail call optimizing recursion
|
||||
@dataclass
|
||||
class Recur(Generic[P]):
|
||||
def __init__(self, *args: P.args, **kwargs: P.kwargs):
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
@dataclass(frozen = True)
|
||||
class Return(Generic[B]):
|
||||
val: B
|
||||
|
||||
@cur2
|
||||
def tco_rec(f: Callable[P, Recur[P] | Return[B] | B], *args: P.args, **kwargs: P.kwargs) -> Callable[P, B]:
|
||||
while True:
|
||||
match f(*args, **kwargs):
|
||||
case Recur(args=args, kwargs=kwargs): #type:ignore
|
||||
pass
|
||||
case Return(val=val)|val:
|
||||
return val #type:ignore
|
Loading…
Reference in a new issue