from __future__ import annotations
import typing
from metadsl import *
from metadsl_rewrite import *
from .conversion import *
from .maybe import *
from .abstraction import *
from .strategies import *
__all__ = ["Either"]
T = typing.TypeVar("T")
U = typing.TypeVar("U")
V = typing.TypeVar("V")
[docs]class Either(Expression, typing.Generic[T, U]):
[docs] @expression
@classmethod
def left(cls, value: T) -> Either[T, U]:
...
[docs] @expression
@classmethod
def right(cls, value: U) -> Either[T, U]:
...
[docs] @expression
def match(self, left: Abstraction[T, V], right: Abstraction[U, V]) -> V:
...
@register_core # type: ignore
@rule
def either_match(l: Abstraction[T, V], r: Abstraction[U, V], t: T, u: U) -> R[V]:
yield Either[T, U].left(t).match(l, r), lambda: l(t) # type: ignore
yield Either[T, U].right(u).match(l, r), lambda: r(u) # type: ignore
@register_convert
@rule
def convert_to_either(x: object) -> R[Maybe[Either[T, U]]]:
"""
Converting to an either should try converting to both types.
If either matches, then that should be the result. If neither
can be converted, then the result should be nothing.
"""
convert_left = (
Converter[T] # type: ignore
.convert(x)
.map(Abstraction.from_fn(Either[T, U].left))
)
convert_right = Converter[U].convert(x).map(Abstraction.from_fn(Either[T, U].right))
return (Converter[Either[T, U]].convert(x), convert_left | convert_right)