suned / pfun

Functional, composable, asynchronous, type-safe Python.

Home Page:https://pfun.dev/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

either usage

galen1090 opened this issue · comments

In this example I just want to transform Right to Data and Left to Error

@dataclass
class Error:
    msg: str

@dataclass
class Data:
    data: str


def i_can_fail2(s: str) -> Either[str, str]:
    # do something 
    return Right(f"{s}!")


def i_can_fail1(s: str) -> Either[str, str]:
    if s == 'illegal value':
        return Left("illegal value")
    return Right('Ok')


def func1() -> Either[Error, Data]:
    # what about a map but only for Left value?
    return i_can_fail1('illegal value').and_then(i_can_fail2).map(lambda x: Data(data=x))

I can do it with few lines of code, but I want to known if there is a proper way to do this.
Thanks

Either is defined as a union type, so the most type friendly way of doing it would be to use isinstance. But even more instructive, why not change the type of the either to Either[Error, Data]?

def i_can_fail(s: str) -> Either[Error, Data]:
    if s == 'illegal value':
        return Left(Error('illegal value))
    return Right(Data('Ok!'))

either = i_can_fail1('illegal value')
if isinstance(either, Left):
     either.get  # type of either.get is inferred to be 'Error'
else:
     either.get  # type of either.get is inferred to be 'Data'

If you wan't to avoid the Error and Data wrappers altogether, but still be able to distinguish between the error and str type during typecheck you could use https://docs.python.org/3/library/typing.html#newtype

Note that i_can_fail(...).map(lambda x: Data(x)) actually produces an Either[str, Data], which doesn't sound like what you want.

Also note that you can achieve the same thing with i_can_fail(...).map(Data) (because constructors are just callables).

But even more instructive, why not change the type of the either to Either[Error, Data]?

because in this use case, i_can_fail1 and i_can_fail2 are not under my control or because they are used by other functions with this signature, and for them Error and Data aren't even in scope.
It's just an example to properly understand how to transform Either to my needs.

because in this use case, i_can_fail1 and i_can_fail2 are not under my control

Ah, I see. In that case I would just convert from Either to Error and Data with isinstance.