grscheller.fp.function
Module fp.functional - compose and partially apply functions.
Not a replacement for the std library's functools
which is more about
modifying function behavior through decorators than functional composition
and application.
FP utilities to manipulate function arguments return values:
- function swap: swap the arguments of a 2 argument function
- function sequenced: convert function to take a sequence of its arguments
- function partial: returns a partially applied function
- function iter_args: function returning an iterator of its arguments
1# Copyright 2024-2025 Geoffrey R. Scheller 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""###Module fp.functional - compose and partially apply functions. 16 17Not a replacement for the std library's `functools` which is more about 18modifying function behavior through decorators than functional composition 19and application. 20 21#### FP utilities to manipulate function arguments return values: 22 23* function **swap:** swap the arguments of a 2 argument function 24* function **sequenced:** convert function to take a sequence of its arguments 25* function **partial:** returns a partially applied function 26* function **iter_args:** function returning an iterator of its arguments 27 28""" 29from __future__ import annotations 30from collections.abc import Callable, Iterator, Sequence 31from typing import Any 32 33__all__ = [ 'swap', 'sequenced', 'partial', 'iter_args' ] 34 35## Functional Utilities 36 37def swap[U,V,R](f: Callable[[U, V], R]) -> Callable[[V, U], R]: 38 """Swap arguments of a two argument function.""" 39 return (lambda v, u: f(u,v)) 40 41def sequenced[R](f: Callable[..., R]) -> Callable[..., R]: 42 """Convert a function with arbitrary positional arguments to one taking 43 a sequence of the original arguments. 44 """ 45 def F(arguments: Sequence[Any]) -> R: 46 return f(*arguments) 47 return F 48 49def partial[R](f: Callable[..., R], *args: Any) -> Callable[..., R]: 50 """Partially apply arguments to a function, left to right. 51 52 * type-wise the only thing guaranteed is the return value 53 * best practice is to either 54 * use `partial` and `sequenced` results immediately and locally 55 * otherwise cast the results when they are created 56 57 """ 58 def wrap(*rest: R) -> R: 59 return sequenced(f)(args + rest) 60 61 return wrap 62 63def iter_args[A](*args: A) -> Iterator[A]: 64 """Function returning an iterators of its arguments. 65 66 * useful for API's with single iterable constructors 67 68 """ 69 for arg in args: 70 yield arg
def
swap(f: 'Callable[[U, V], R]') -> 'Callable[[V, U], R]':
38def swap[U,V,R](f: Callable[[U, V], R]) -> Callable[[V, U], R]: 39 """Swap arguments of a two argument function.""" 40 return (lambda v, u: f(u,v))
Swap arguments of a two argument function.
def
sequenced(f: 'Callable[..., R]') -> 'Callable[..., R]':
42def sequenced[R](f: Callable[..., R]) -> Callable[..., R]: 43 """Convert a function with arbitrary positional arguments to one taking 44 a sequence of the original arguments. 45 """ 46 def F(arguments: Sequence[Any]) -> R: 47 return f(*arguments) 48 return F
Convert a function with arbitrary positional arguments to one taking a sequence of the original arguments.
def
partial(f: 'Callable[..., R]', *args: Any) -> 'Callable[..., R]':
50def partial[R](f: Callable[..., R], *args: Any) -> Callable[..., R]: 51 """Partially apply arguments to a function, left to right. 52 53 * type-wise the only thing guaranteed is the return value 54 * best practice is to either 55 * use `partial` and `sequenced` results immediately and locally 56 * otherwise cast the results when they are created 57 58 """ 59 def wrap(*rest: R) -> R: 60 return sequenced(f)(args + rest) 61 62 return wrap
def
iter_args(*args: 'A') -> 'Iterator[A]':
64def iter_args[A](*args: A) -> Iterator[A]: 65 """Function returning an iterators of its arguments. 66 67 * useful for API's with single iterable constructors 68 69 """ 70 for arg in args: 71 yield arg
Function returning an iterators of its arguments.
- useful for API's with single iterable constructors