diff --git a/func.py b/func.py deleted file mode 100644 index 07dcde7..0000000 --- a/func.py +++ /dev/null @@ -1,54 +0,0 @@ - -#==================================================================== -#===================== Function Decorators ========================== -#==================================================================== - -def log(f): - def g(*args): - r = f(*args) - print("Calculating: %s(%s) = %s" % ( str(f).split(" ")[1], str(",".join(map(str,list(args)))), str(r)) ) - return r - return g - -def maybe(f): - def g(*args): - try: return f(*args) - except: return None - return g - -def memoize(f): - mem = {} - def g(*args): - if args in mem: - print("Remember: f%s = %s" % (args,mem[args])) - return mem[args] - r = f(*args) - if r != None: - print("Memoize: f%s = %s" % (args,r)) - mem[args] = r - return r - return g - -#docurry -def curryD(n): - def deco(f): - if n == 1: return f - return lambda x: curry(fix(f, x), n-1) - return deco - - -#========================================================== -#===================== Functions ========================== -#========================================================== - -#======== Composition ================ -def fix(f, x): - return lambda *args: f(*([x]+list(args))) - -def curry(f, n): - if n == 1: return f - return lambda x: curry(fix(f, x), n-1) - -def comp(g,f): - return lambda *args: g(f(*args)) - diff --git a/func/__init__.py b/func/__init__.py deleted file mode 100644 index e1000d0..0000000 --- a/func/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ - -from func.func import * -from func.list import * -from func.string import * -from func.io import * - - diff --git a/func/func.py b/func/func.py deleted file mode 100644 index ae2ca3d..0000000 --- a/func/func.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: utf-8 -*- -from functools import * -from itertools import * - - -def compose(g,f): - return lambda *args: g(f(*args)) - - -def comp(*args): - return reduce(compose, args) - -def maybe(f): - def g(*args): - try: return f(*args) - except: return None - return g - -def memoize(f): - mem = {} - def g(*args): - if args in mem: - print("Remember: f%s = %s" % (args,mem[args])) - return mem[args] - r = f(*args) - if r != None: - print("Memoize: f%s = %s" % (args,r)) - mem[args] = r - return r - return g - -def curryD(n): - def deco(f): - if n == 1: return f - return lambda x: curry(fix(f, x), n-1) - return deco - -def fix(f, x): - return lambda *args: f(*([x]+list(args))) - -def curry(f, n): - if n == 1: return f - return lambda x: curry(fix(f, x), n-1) - - - diff --git a/func_py/__init__.py b/func_py/__init__.py new file mode 100644 index 0000000..561bec1 --- /dev/null +++ b/func_py/__init__.py @@ -0,0 +1,7 @@ + +from .func import * +#from .list import * +#from .string import * +#from .io import * + + diff --git a/func/debug.py b/func_py/debug.py similarity index 100% rename from func/debug.py rename to func_py/debug.py diff --git a/func_py/func.py b/func_py/func.py new file mode 100644 index 0000000..2c3bfaf --- /dev/null +++ b/func_py/func.py @@ -0,0 +1,113 @@ +from inspect import signature, Parameter, _empty +from functools import partial +from typing import Any + +class Function: + + #@staticmethod + #def add_missing_signature(f): + + __match_args__ = ["signature", "is_pure"] + + @staticmethod + def compose(f, g): + if type(g) == Function: + g = g.original_func + else: + #whatif lambda? + if "__name__" in dir(g) and g.__name__ == "": + sig_g = signature(g) + g.__signature__ = sig_g.replace(parameters=[ + Parameter(name=name, annotation=Any, kind=Parameter.POSITIONAL_ONLY) + for name, param in sig_g.parameters.items() if param.default == _empty + ], return_annotation=Any) + else: + pass + #its a functools.partial func with no name... + + + if type(f) == Function: + f = f.original_func + + sig_g = signature(g) + g_req_params = [v for k, v in sig_g.parameters.items() if v.default == _empty] + + g_typed_req_params = [p if p.annotation == _empty else Parameter(name=p.name, annotation=Any, kind=Parameter.POSITIONAL_ONLY) for p in g_req_params] + + def h(*args, **kwargs): + return f(g(*args, **kwargs)) + + f_ret_type = signature(f).return_annotation + h.__signature__ = sig_g.replace(parameters=g_typed_req_params, return_annotation=Any if f_ret_type == _empty else f_ret_type) + return Function(h) + + def __init__(self, f): + self.original_func = f + self.signature = signature(f) #TODO: change to support pattern matching: sig ((int, str), {"name": str}) + self.__signature__ = signature(f) + self.cache = {} + self.is_pure = True + + def __str__(self): + return str(signature(self.original_func)) + + def __repr__(self): + return str(self) + + def __mul__(self, g): + return Function.compose(self, g) + + def __rmul__(self, g): + return Function.compose(g, self) + + @property + def required_args(self): + return [(k, v) for k, v in signature(self.original_func).parameters.items() if v.default == _empty] + + def __call__(self, *args, **kwargs): + #currying: if less than the needed args are given return a partial function + if len(args) < len(self.required_args): + sig = signature(self.original_func) + f = partial(self.original_func, *args) + req_params = [v for k, v in sig.parameters.items() if v.default == _empty] + remaining_params = req_params[len(args):] + f.__signature__ = sig.replace(parameters=remaining_params, return_annotation=Any if sig.return_annotation == _empty else sig.return_annotation) + return Function(f) + + r = self.original_func(*args, **kwargs) + if self.is_pure: + pass + #do caching + + return r + + + +@Function +def inc(x: int) -> int: + return x + 1 + +@Function +def multi(a: int, b: int) -> int: + return a * b + +@Function +def add(a: int, b: int) -> int: + return a + b + + + +#print(add(2,3)) +#print((inc * add)(2,3)) +#print((inc * add)) + +#print(add(99)) +print((add(99) * multi(100) * add(2) * (lambda x: x + 1))) + +print(Function.compose(lambda x: x + 1, lambda x: x * 3)) + +print(signature(Function.compose(lambda x: x + 1, lambda x: x * 3))) + + +#print(inspect.signature(add)) +#print(inspect.signature(add).parameters) diff --git a/func/io.py b/func_py/io.py similarity index 100% rename from func/io.py rename to func_py/io.py diff --git a/func/lib.py b/func_py/lib.py similarity index 100% rename from func/lib.py rename to func_py/lib.py diff --git a/func/list.py b/func_py/list.py similarity index 100% rename from func/list.py rename to func_py/list.py diff --git a/func/monad.py b/func_py/monad.py similarity index 100% rename from func/monad.py rename to func_py/monad.py diff --git a/func/path.py b/func_py/path.py similarity index 100% rename from func/path.py rename to func_py/path.py diff --git a/func/string.py b/func_py/string.py similarity index 100% rename from func/string.py rename to func_py/string.py diff --git a/pyproject.toml b/pyproject.toml index 9e717be..cffcebe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.poetry] -name = "func-py" +name = "func_py" version = "0.1.0" description = "" authors = ["Tobias "] @@ -13,3 +13,6 @@ python = "^3.12" [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" + + +