Implémentation de kotlin.Triple en JavaScript, TypeScript et Python
Publié le 25 December 2023
Créer une implémentation complète de la classe kotlin.Triple en JavaScript, TypeScript et Python en utilisant la programmation fonctionnelle.
Note : Les types Maybe
, Either
, Result
ne font pas partie du langage de base en JavaScript ou TypeScript, donc il faut les implémenter nous-mêmes.
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
Pour créer une implémentation en Python en utilisant pydantic
pour la validation des types et pymonad
pour les monades :
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}')
-
pydantic
pour définir la classeTriple
avec des champs typés. -
La méthode
divide_by
utilise la monadeEither
depymonad
pour gérer les erreurs potentielles résultant de la division par zéro. -
Validation personnalisée pour s’assurer que la valeur de
b
n’est pas égale à zéro. Si elle est égale à zéro, une exception est levée, etpymonad
capture cette exception pour renvoyer un résultatLeft
indiquant l’erreur.