Implementação de kotlin.Triple em JavaScript, TypeScript e Python
Publié le 25 December 2023
Tempo de leitura : 2 min Criar uma implementação completa da classe kotlin.Triple em JavaScript, TypeScript e Python utilizando a programação funcional.
Nota :Os tipos`Maybe`, Either, `Result`não fazem parte da linguagem de base em JavaScript ou TypeScript, portanto precisamos implementá-los nós mesmos.
JavaScript
//javascript
// Maybe type
const Maybe = (value) => ({
map: (fn) => (value !== null && value !== undefined ? Maybe(fn(value)) : Maybe(null)),
flatMap: (fn) => (value !== null && value !== undefined ? fn(value) : Maybe(null)),
getOrElse: (defaultValue) => (value !== null && value !== undefined ? value : defaultValue),
});
// Either type
const Either = {
Left: (value) => ({
map: (fn) => Either.Left(value),
flatMap: (fn) => Either.Left(value),
getOrElse: (defaultValue) => defaultValue,
isLeft: true,
isRight: false,
}),
Right: (value) => ({
map: (fn) => Either.Right(fn(value)),
flatMap: (fn) => fn(value),
getOrElse: (defaultValue) => value,
isLeft: false,
isRight: true,
}),
};
// Triple class
class Triple {
constructor(a, b, c) {
this.a = a;
this.b = b;
this.c = c;
}
map(fn) {
return new Triple(fn(this.a), fn(this.b), fn(this.c));
}
static of(a, b, c) {
return new Triple(a, b, c);
}
// Example method using Maybe and Either
divideBy(other) {
return Maybe(this.b)
.flatMap((numerator) =>
Maybe(other)
.flatMap((denominator) =>
denominator !== 0
? Either.Right(numerator / denominator)
: Either.Left('Division by zero')
)
)
.getOrElse(Either.Left('Invalid input'));
}
}
// Example usage
const triple = Triple.of(1, 2, 3);
const result = triple.map((x) => x * 2);
console.log(result); // Triple { a: 2, b: 4, c: 6 }
const divisionResult = triple.divideBy(2);
console.log(divisionResult); // Either.Right { value: 1 }
const invalidDivisionResult = triple.divideBy(0);
console.log(invalidDivisionResult); // Either.Left { value: 'Division by zero' }
TypeScript
//Typescript
// Maybe type
// noinspection JSAnnotator
type Maybe<T> = {
map<U>(fn: (value: T) => U): Maybe<U>;
flatMap<U>(fn: (value: T) => Maybe<U>): Maybe<U>;
getOrElse(defaultValue: T): T;
};
const just = <T>(value: T): Maybe<T> => ({
map: <U>(fn: (value: T) => U) => just(fn(value)),
flatMap: <U>(fn: (value: T) => Maybe<U>) => fn(value),
getOrElse: (_: T) => value,
});
const nothing = <T>(): Maybe<T> => ({
map: <U>(_: (value: T) => U) => nothing<U>(),
flatMap: <U>(_: (value: T) => Maybe<U>) => nothing<U>(),
getOrElse: (defaultValue: T) => defaultValue,
});
// Either type
type Either<L, R> = {
map<U>(fn: (value: R) => U): Either<L, U>;
flatMap<U>(fn: (value: R) => Either<L, U>): Either<L, U>;
getOrElse(defaultValue: R): R;
isLeft: boolean;
isRight: boolean;
};
const left = <L, R>(value: L): Either<L, R> => ({
map: <U>(_: (value: R) => U) => left<L, U>(value),
flatMap: <U>(_: (value: R) => Either<L, U>) => left<L, U>(value),
getOrElse: (defaultValue: R) => defaultValue,
isLeft: true,
isRight: false,
});
const right = <L, R>(value: R): Either<L, R> => ({
map: <U>(fn: (value: R) => U) => right<L, U>(fn(value)),
flatMap: <U>(fn: (value: R) => Either<L, U>) => fn(value),
getOrElse: (_: R) => value,
isLeft: false,
isRight: true,
});
// Triple class
class Triple<T> {
constructor(public a: T, public b: T, public c: T) {}
map<U>(fn: (value: T) => U): Triple<U> {
return new Triple<U>(fn(this.a), fn(this.b), fn(this.c));
}
static of<T>(a: T, b: T, c: T): Triple<T> {
return new Triple<T>(a, b, c);
}
// Example method using Maybe and Either
divideBy(other: T): Either<string, number> {
return just(this.b)
.flatMap((numerator) =>
just(other)
.flatMap((denominator) =>
denominator !== 0 ? right(numerator / denominator) : left('Division by zero')
)
)
.getOrElse(left('Invalid input'));
}
}
// Example usage
const triple = Triple.of(1, 2, 3);
const result = triple.map((x) => x * 2);
console.log(result); // Triple { a: 2, b: 4, c: 6 }
const divisionResult = triple.divideBy(2);
console.log(divisionResult); // Either.Right { value: 1 }
const invalidDivisionResult = triple.divideBy(0);
console.log(invalidDivisionResult); // Either.Left { value: 'Division by zero' }
Python, pydantic, pymonad
Para criar uma implementação em Python usando`pydantic`para a validação dos tipos e`pymonad`para as mônadas :
Instalar as dependências :
pip install pydantic pymonad
from pymonad.either import Either, Left, Right
from pydantic import BaseModel, ValidationError, validator
# Définition de la classe Triple avec Pydantic
class Triple(BaseModel):
a: int
b: int
c: int
@validator('b')
def validate_b(cls, b, values):
if b == 0:
raise ValueError('Division by zero is not allowed')
return b
# Méthode utilisant Either pour la gestion des erreurs
def divide_by(self, other):
def division(numerator, denominator):
return Right(numerator / denominator)
def handle_error(error):
return Left(str(error))
return Either(lambda: division(self.b, other)).or_else(handle_error)
# Exemple d'utilisation
try:
triple = Triple(a=1, b=2, c=3)
result = triple.divide_by(2)
if result.is_right:
print(f'Division result: {result.value}')
else:
print(f'Error: {result.value}')
except ValidationError as e:
print(f'Validation Error: {e}')
except Exception as e:
print(f'An unexpected error occurred: {e}')
Neste exemplo:
-
pydantic`para definir a classe`Triple`com campos tipados. O método`divide_by`utiliza a mônada`Eitherde `pymonad`para lidar com os erros potenciais resultantes da divisão por zero - Validação personalizada para garantir que o valor de`b`não é igual a zero. Se for igual a zero, uma exceção é lançada, e`pymonad`captura essa exceção para retornar um resultado`Left`indicando o erro.