Skip to content

Commit

Permalink
Adds compose(f, g) function.
Browse files Browse the repository at this point in the history
  • Loading branch information
sobolevn committed Feb 18, 2019
1 parent 856cd77 commit 59779f1
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 1 deletion.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
We follow Semantic Versions since the `0.1.0` release.


## WIP

### Features

- Adds `compose` function


## Version 0.4.0 aka Goodbye, Monads!

### Features
Expand Down
16 changes: 16 additions & 0 deletions docs/pages/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,22 @@ with these implementations:
- https://github.com/deadpixi/contracts


compose
-------

We also ship an utility function to compose two different functions together.

.. code:: python
from returns.functions import compose
bool_after_int = compose(int, bool)
bool_after_int('1') # => True
bool_after_int('0') # => False
Composition is also type-safe.
The only limitation is that we only support
functions with one argument and one return.

API Reference
-------------
Expand Down
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ m2r==0.2.1
tomlkit==0.5.3

# Dependencies of our project:
typing-extensions==3.7.2.
typing-extensions==3.7.2
12 changes: 12 additions & 0 deletions returns/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,15 @@ def decorator(*args, **kwargs):
except UnwrapFailedError as exc:
return exc.halted_container
return decorator


def compose(first, second):
"""
Allows function composition.
Works as: second . first
You can read it as "second after first".
We can only compose functions with one argument and one return.
"""
return lambda argument: second(first(argument))
10 changes: 10 additions & 0 deletions returns/functions.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ _ReturnsContainerType = TypeVar(
bound=Callable[..., Container],
)

_FirstType = TypeVar('_FirstType')
_SecondType = TypeVar('_SecondType')
_ThirdType = TypeVar('_ThirdType')

def is_successful(container: _ContainerType) -> bool:
...
Expand All @@ -28,3 +31,10 @@ def safe(
function: Callable[..., _ReturnType],
) -> Callable[..., Result[_ReturnType, Exception]]:
...


def compose(
first: Callable[[_FirstType], _SecondType],
second: Callable[[_SecondType], _ThirdType],
) -> Callable[[_FirstType], _ThirdType]:
...
19 changes: 19 additions & 0 deletions tests/test_functions/test_compose.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-

from returns.functions import compose


def _first(a: int) -> str:
return str(a)


def _second(b: str) -> bool:
return bool(b)


def test_function_composition():
"""Ensures that functions can be composed and return type is correct."""
second_after_first = compose(_first, _second)

assert second_after_first(1) is True
assert second_after_first(0) is True

0 comments on commit 59779f1

Please sign in to comment.