From adddc0704d0eb769e2bf0b8c02fae1e39aa40c5a Mon Sep 17 00:00:00 2001 From: Emi Simpson Date: Tue, 7 Feb 2023 11:59:55 -0500 Subject: [PATCH] Some funky lil funktions --- emis_funky_funktions.py | 155 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 emis_funky_funktions.py diff --git a/emis_funky_funktions.py b/emis_funky_funktions.py new file mode 100644 index 0000000..9e70b21 --- /dev/null +++ b/emis_funky_funktions.py @@ -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 \ No newline at end of file