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}')
- 
pydanticpour définir la classeTripleavec des champs typés. - 
La méthode
divide_byutilise la monadeEitherdepymonadpour gérer les erreurs potentielles résultant de la division par zéro. - 
Validation personnalisée pour s’assurer que la valeur de
bn’est pas égale à zéro. Si elle est égale à zéro, une exception est levée, etpymonadcapture cette exception pour renvoyer un résultatLeftindiquant l’erreur.