-
-
Save LeeeeT/8c9a8bcef17a5705455de5dfc7743d97 to your computer and use it in GitHub Desktop.
I do not 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 Final, NewType | |
class Compose[Value, Result]: | |
def __init__[Intermediate](self, second: Callable[[Intermediate], Result], first: Callable[[Value], Intermediate]) -> None: | |
self.second: Final = second | |
self.first: Final = first | |
def __call__(self, value: Value) -> Result: | |
return self.second(self.first(value)) | |
@dataclass(frozen=True) | |
class Some[Value]: | |
value: Value | |
class Nothing: | |
pass | |
type Option[Value] = Nothing | Some[Value] | |
def option_join[Value](optional_option: Option[Option[Value]]) -> Option[Value]: | |
match optional_option: | |
case Nothing(): | |
return Nothing() | |
case Some(option): | |
return option | |
@dataclass(frozen=True) | |
class OptionLift[Value, Result]: | |
function: Callable[[Value], Result] | |
def __call__(self, value: Value) -> Option[Result]: | |
return Some(self.function(value)) | |
@dataclass(frozen=True) | |
class OptionMap[Value, Result]: | |
function: Callable[[Value], Result] | |
def __call__(self, option: Option[Value]) -> Option[Result]: | |
match option: | |
case Nothing(): | |
return Nothing() | |
case Some(value): | |
return OptionLift(self.function)(value) | |
@dataclass(frozen=True) | |
class OptionBind[Value, Result]: | |
function: Callable[[Value], Option[Result]] | |
def __call__(self, option: Option[Value]) -> Option[Result]: | |
return option_join(OptionMap(self.function)(option)) | |
class OptionCompose[Value, Result]: | |
def __init__[Intermediate](self, second: Callable[[Intermediate], Option[Result]], first: Callable[[Value], Option[Intermediate]]) -> None: | |
self.second: Final = second | |
self.first: Final = first | |
def __call__(self, value: Value) -> Option[Result]: | |
return OptionBind(self.second)(self.first(value)) | |
class Valid: | |
pass | |
class Invalid: | |
pass | |
type ValidationResult = Valid | Invalid | |
type Validator[T] = Callable[[T], ValidationResult] | |
@dataclass(frozen=True) | |
class Greater: | |
compared: int | |
def __call__(self, value: int) -> 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() | |
Positive = NewType("Positive", int) | |
positive = Compose(OptionMap(Positive), AsParser(Greater(0))) | |
match positive(0): | |
case Nothing(): | |
pass | |
case Some(value): | |
value: Positive = value |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment