Levage à Scala
- Transformer des méthodes en fonctions
- Transformer des fonctions pures en foncteurs dans Scala
- Transformer des fonctions partielles en fonctions dans Scala
- Transformateurs Monad dans Scala
- Conclusion
Cet article parlera de levage dans le langage de programmation Scala. Levage a différentes significations; cela dépend du contexte dans lequel nous l’utilisons.
Regardons-les un par un.
Transformer des méthodes en fonctions
Nous rencontrons parfois des situations où nous voulons transformer des méthodes en fonctions. Ceci est un exemple de levage.
Par exemple, supposons que nous ayons les méthodes suivantes :
def mul(x: Int) = x*5
def isEven(x: Int) = x%2==0
Maintenant, nous pouvons composer ces méthodes comme ci-dessous :
isEven(mul(4))
Mais que se passe-t-il si nous voulons que cette composition se produise de manière fonctionnelle ? Ensuite, nous devons transformer ces méthodes ci-dessus en fonctions.
Cela peut être fait en les soulevant à l’aide du symbole _
dans Scala.
val mulAns = mul _
val isEvenAns = isEven _
Maintenant, nous pouvons les composer fonctionnellement comme ci-dessous :
( mulAns andThen isEvenAns)(5)
Code de travail complet :
object MyClass {
def mul(x: Int) = x*5
def isEven(x: Int) = x%2==0
def main(args: Array[String])
{
println(isEven(mul(4)));
val mulAns = mul _
val isEvenAns = isEven _
println(( mulAns andThen isEvenAns)(5))
}
}
Production:
true
false
Explication:
La première sortie est true
car 4 est multiplié par 5, ce qui donne 20. Ce 20 est passé en paramètre à la fonction isEven
.
La deuxième sortie est false
car 5 est d’abord multiplié par 5, puis son résultat est vérifié dans la fonction isEven
.
Transformer des fonctions pures en foncteurs dans Scala
Le foncteur fait référence au mappage entre les catégories, un peu comme une fonction d’entités ou d’objets. Par exemple, nous avons des catégories A
et B
et un foncteur F
qui associe les objets A
aux objets B
.
trait Functor[F[_]] {
def mapping[A, B](X: F[A])(f: A => B): F[B]
def lifting[A, B](f: A => B): F[A] => F[B] =
X => map(X)(f)
}
Dans ce contexte, le lifting consiste à prendre une fonction de A=>B
et à la transformer en foncteur en en faisant une fonction de la forme F[A] => F[B]
. Lorsque vous travaillez avec des types de données imbriqués, cela peut être très utile.
Transformer des fonctions partielles en fonctions dans Scala
Dans ce contexte, le lifting fait référence à l’extension du domaine. Les fonctions partielles sont des types de fonctions qui peuvent être appliquées aux sous-domaines de valeurs.
Mais parfois, nous pourrions vouloir étendre leur domaine, et la levée nous aide à y parvenir.
Supposons que nous ayons une fonction partielle qui donne la racine carrée d’un nombre positif.
val sqrt: PartialFunction[Double, Double] =
{
case temp if temp >= 0 => Math.sqrt(temp)
}
Maintenant, nous pouvons étendre le domaine de notre fonction partielle en utilisant la méthode lift
pour la rendre plus élégante :
def getSqrtRootPartialFunction(t: Double) =
{
sqrt.lift(t).map(ans => s"Square root of ${t} is ${ans}")
.getOrElse(s"Cannot calculate square root for t")
}
Code de travail complet :
object MyClass {
val sqrt: PartialFunction[Double, Double] = {
case temp if temp >= 0 => Math.sqrt(temp)
}
def getSqrtRootPartialFunction(t: Double) = {
sqrt.lift(t).map(ans => println(s"Square root of ${t} is ${ans}"))
.getOrElse(println(s"Cannot calculate square root for t"))
}
def main(args: Array[String])
{
getSqrtRootPartialFunction(35)
}
}
Production:
Square root of 35.0 is 5.916079783099616
Explication:
Donc, ce que la levée de la fonction sqrt
a fait ici, c’est qu’elle a étendu le domaine à un double entier de PartialFunction[Double, Double]
à une Function[Double, Option[Double]]
.
Parfois, la levée des fonctions partielles est utilisée pour éviter l’exception index out of bound
.
Seq("1", "2", "3").lift(1) // Some("2")
Seq("1", "2", "3").lift(7) // none returned
Le domaine a été étendu de String
à Option[String]
. Ainsi, lorsque nous essayons d’accéder à une valeur hors limite, le Seq
levé renvoie None
au lieu de lancer une exception out of bound
.
Transformateurs Monad dans Scala
La combinaison de monades se fait à l’aide de transformateurs de monades. Disons que nous avons deux Futures
:
val helloWorld: Future[Option[String]] = Future.successful(Some("hello world"))
val language: Future[String] = Future.successful("this is Scala language")
Maintenant, comme les deux Futures
ont des domaines différents, nous pouvons utiliser des transformateurs de monade en élevant language
à OptionT
. Ainsi, nous pouvons gérer le résultat de manière plus cohérente :
def MonadTransformer() = {
val message: OptionT[Future, String] = for {
hello <- OptionT(helloWorld)
name <- OptionT.liftF(language)
} yield println(s"$hello $name")
val result: Future[Option[String]] = message.value
Await.result(result, 1 second)
}
Conclusion
Dans cet article, nous avons appris le concept de levage et ce qu’il signifie dans différents contextes. Il est très utile d’écrire notre code d’une manière plus composable et idiomatique, ce qui nous permet de nous concentrer davantage sur la logique métier du code plutôt que de perdre du temps à en construire différentes parties.