-
-
Save LeeeeT/6e6b4c5eb578cf2797ae4133d06ea23c to your computer and use it in GitHub Desktop.
I swear to God
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import annotations | |
from collections.abc import Callable | |
from dataclasses import dataclass | |
from typing import cast, Final, NewType | |
class Compose[A, C]: | |
def __init__[B](self, f: Callable[[B], C], g: Callable[[A], B]) -> None: | |
self.f: Final = f | |
self.g: Final = g | |
def __call__(self, value: A) -> C: | |
return self.f(self.g(value)) | |
@dataclass(frozen=True) | |
class Some[T]: | |
value: T | |
class Nothing: | |
pass | |
type Option[T] = Nothing | Some[T] | |
def option_join[T](value: Option[Option[T]]) -> Option[T]: | |
match value: | |
case Nothing(): | |
return Nothing() | |
case Some(v): | |
return v | |
@dataclass(frozen=True) | |
class OptionLift[T, F]: | |
f: Callable[[T], F] | |
def __call__(self, value: T) -> Option[F]: | |
return Compose(Some, self.f)(value) | |
@dataclass(frozen=True) | |
class OptionMap[T, F]: | |
f: Callable[[T], F] | |
def __call__(self, value: Option[T]) -> Option[F]: | |
match value: | |
case Nothing(): | |
return Nothing() | |
case Some(v): | |
return OptionLift(self.f)(v) | |
@dataclass(frozen=True) | |
class OptionBind[T, F]: | |
f: Callable[[T], Option[F]] | |
def __call__(self, value: Option[T]) -> Option[F]: | |
return option_join(OptionMap(self.f)(value)) | |
class OptionCompose[A, C]: | |
def __init__[B](self, f: Callable[[B], Option[C]], g: Callable[[A], Option[B]]) -> None: | |
self.f: Final = f | |
self.g: Final = g | |
def __call__(self, value: A) -> Option[C]: | |
return OptionBind(self.f)(self.g(value)) | |
class Valid: | |
pass | |
class Invalid: | |
pass | |
type ValidationResult = Valid | Invalid | |
type Validator[T] = Callable[[T], ValidationResult] | |
@dataclass(frozen=True) | |
class Greater: | |
compared: float | |
def __call__(self, value: float) -> ValidationResult: | |
return Valid() if value > self.compared else Invalid() | |
@dataclass(frozen=True) | |
class AsParser[T]: | |
validator: Validator[T] | |
def __call__(self, value: T) -> Option[T]: | |
match self.validator(value): | |
case Valid(): | |
return Some(value) | |
case Invalid(): | |
return Nothing() | |
class Its[T]: | |
pass | |
@dataclass(frozen=True) | |
class ISwearToGod[T]: | |
its: type[Its[T]] | |
def __call__(self, value: object) -> T: | |
return cast(T, value) | |
_Positive = NewType("_Positive", int) | |
type Positive = _Positive | |
validator = Greater(0) | |
swear = ISwearToGod(Its[Positive]) | |
positive = OptionCompose(OptionLift(swear), AsParser(validator)) | |
match positive(0): | |
case Nothing(): | |
pass | |
case Some(v): | |
v: Positive = v |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment