Skip to content

Extendable typed functions #447

Closed
Closed

Description

@sobolevn

Ok, here's the deal.

We need to somehow make our pointfree and other helper functions trully generic.
Currently we have a hardcoded set of containers that each of these functions support.

It is not a scallable solution.

Let's say I want to create a new monad called Example[T] extends Monad[T].

Here's what I need to do:

from typing import Callable, Generic, TypeVar
from returns.typeclasses.monad import Monad
from returns.hkt import Kind

T = TypeVar('T')
N = TypeVar('N')

class Example(Kind['Example', T], Generic[T], Monad[T]):
    def bind(self, function: Callable[[T], Kind['Example', N]]) -> 'Example[N]':
         ...

It works just fine! Now, what about using bind() pointfree function? It will work in runtime, but fail during the type-checking.
Because it is defined using overloads and is hardcoded.

The problem is that HKT functions are not supported. And possibly won't be supported anytime soon (unless get_function_sig_hook will be released).

I suggest to rewrite it as follows (let's start with the contract definition):

K = TypeVar(K, bound=Monad)

@contract
def bind(instance: Monad[T], function: Callable[[T], Monad[N]]) -> Monad[N]:
     return instance.bind(function)

And then add a special case for our existing containers:

from returns.pointfree import bind

@bind.negotiate
def bind_maybe(instance: Maybe[T], function: Callable[[T], Maybe[N]]) -> Maybe[N]:
    """Case for Maybe."""

@bind.negotiate
def bind_example(instance: Example[T], function: Callable[[T], Example[N]]) -> Example[N]:
    """Case for Example."""

This way we would provide:

  1. Default implementation for types we own
  2. Ability to add your own types and extend the typing of existing things

Activity

  1. sobolevn commented on Jul 5, 2020

    @sobolevn
    MemberAuthor

    Implementation notes:

    1. Functions under @bind.negotiate should not have body, can we check that? @overload looks like it does something like that
    2. Functions under @bind.negotiate must be typechecked with the @contract definition. But, not the regular OOP way (sorry, Liskov)

    Related #446 #408

  2. sobolevn commented on Jul 12, 2020

    @sobolevn
    MemberAuthor

    Done by #446

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions