Fonction Currying à Swift

introduction

Le currying est une caractéristique de la plupart des langages de programmation modernes. Il traduit une fonction unique avec plusieurs arguments en une série de fonctions, chacune avec un argument. Cela permet essentiellement de stocker des fonctions dans des variables et de créer des fonctions qui renvoient des fonctions..

Bien que cela puisse sembler un concept étrange au début, il s’agit d’une technique puissante qui peut parfois être très utile. Dans ce tutoriel, je vais vous montrer comment tirer parti de la fonction currying dans Swift..

1. Fonction curry avec des classes

Avant de définir nos propres fonctions personnalisées, je vais d'abord vous montrer un exemple simple de currying dans Swift à l'aide de classes..

Ouvrez Xcode, créez un nouveau terrain de jeu iOS ou OS X et ajoutez-y le code suivant:

class Car vitesse var = 0 fonction accélérerPar (facteur: Int) -> Int vitesse + = vitesse de retour du facteur let car1 = Car ()

Nous définissons une classe de base avec une propriété et une méthode ou fonction d'instance. Nous créons également une instance de la classe, voiture1. Nous pouvons appeler le AccélérerPar (_ :) méthode de notre Voiture instance avec le code suivant:

car1.accelerateBy (10)

Il existe cependant une autre façon d’exécuter cette méthode en utilisant la fonction currying. Dans l'exemple ci-dessus, vous appelez la méthode directement sur voiture1 malgré le fait que la méthode soit définie dans le Voiture classe. La méthode que nous avons écrite n’est pas spécifique à la voiture1 exemple, mais plutôt le Voiture classe. Lorsque vous appelez cette méthode, ce qui se passe réellement, c’est que Swift s’adresse en premier à la Voiture classe, récupère le AccélérerPar (_ :) method, indique à la méthode quelle instance est utilisée, puis exécute une méthode modifiée spécifique à cette instance. Pour vous montrer comment cela fonctionne, ajoutez la ligne suivante à votre terrain de jeu:

Car.accelerateBy (car1)

Ce que nous faisons ici est d'accéder à la AccélérerPar (_ :) méthode du Voiture classe et passage, en tant que paramètre, sur laquelle nous voulons que cette fonction soit exécutée. Dans l'encadré de votre terrain de jeu, vous pouvez voir que le résultat de cette méthode est une autre fonction..

Ce que cela (Une fonction) résultat représente est en fait un nouveau AccélérerPar (_ :) méthode spécifique à la voiture1 exemple. Cette fonction retournée est unique en ce sens qu'elle fait spécifiquement référence à voiture1de la vitesse propriété plutôt que la méthode générique que vous avez définie précédemment, qui peut référencer la la vitesse propriété de tout Voiture exemple.

Comme vous vous en doutez, nous pouvons transmettre de nouveaux paramètres à cette fonction renvoyée afin de l'exécuter comme nous le faisons habituellement. Ajoutez la ligne de code suivante à votre terrain de jeu:

Car.accelerateBy (car1) (10)

Avec ce code, on passe dix en tant que paramètre dans l'unique AccélérerPar (_ :) méthode et obtenir voiture1la vitesse actuelle est retournée à la suite.

Toutes nos félicitations! Vous venez de profiter de la fonction currying à Swift pour la toute première fois.

En plus de réunir plusieurs fonctions, le Fonction Par conséquent, le code renvoyé peut également être stocké dans une variable. Cela vous permet de stocker et de réutiliser rapidement le AccélérerPar (_ :) méthode spécifique à votre voiture1 exemple. Ajoutez les lignes suivantes à votre terrain de jeu:

Soit a = Car.accelerateBy (car1) a (10) a (20) a (30)

Vous pouvez voir cette variable une se comporte maintenant comme n'importe quelle autre fonction définie globalement. L'avantage est qu'il est spécifique à un particulier Voiture exemple, qui peut être défini au moment de l’exécution plutôt que lors de la compilation. Dans votre terrain de jeu, vous pouvez voir les résultats attendus affichés dans la barre latérale..

Enfin, je vais vous montrer comment retourner une fonction d’une autre fonction en réimplémentant le comportement de Voiture classe que nous venons de regarder. Nous allons le faire en définissant une fonction qui retourne une autre fonction. Dans votre code, cette fonction pourrait ressembler à ceci:

func someFunction (entrée: AnyObject) -> (AnyObject) -> AnyObject // Fait quelque chose pour retourner une fonction 

Nous définissons le une fonction (_ :) fonction, qui accepte un AnyObject paramètre et renvoie une autre fonction qui accepte également un AnyObject paramètre qui renvoie un AnyObject résultat. Ce type de définition de fonction peut sembler très déconcertant et décourageant au premier abord. Pour simplifier, nous pouvons profiter de la typealias mot-clé dans Swift pour mapper un nouveau nom sur n'importe quel type de données.

Ajoutez le code suivant à votre terrain de jeu:

typealias IntFunction = (Int) -> Int func accélérationForCar (voiture: voiture) -> IntFunction return Car.accelerateBy (voiture) let newA = accélérationForCar (voiture1) nouveauA (10)

En utilisant typealias mapper le nom de IntFunction au (Int) -> Int type de données, nous avons grandement simplifié la accelerationForCar (_ :) définition de la fonction. le (Int) -> Int type de données représente simplement une fonction qui accepte un Int paramètre et retourne un Int valeur.

Cette nouvelle fonction utilise le comportement intégré du Voiture classe pour retourner un IntFunction objet qui peut ensuite être stocké dans une variable et utilisé comme nous le faisions avant.

2. Fonctions personnalisées au curry

Bien que le comportement de curry des fonctions intégrées dans Swift soit très utile, vous souhaiterez peut-être créer vos propres fonctions qui ne sont pas liées aux classes. Pour cette partie du didacticiel, nous allons d’abord utiliser l’exemple d’une fonction qui multiplie un autre nombre par une valeur constante..

Imaginez que vous souhaitiez créer une fonction qui accepte un nombre unique et le multiplie par 5. Cette fonction simple pourrait ressembler à ceci:

func multiplyBy5 (a: Int) -> Int return a * 5

Maintenant, imaginez que vous ayez besoin d’une fonction similaire, mais que vous deviez la multiplier par 10 au lieu de 5. Ensuite, vous avez besoin d’une autre fonction pour la multiplier par 20. Vous pouvez créer trois fonctions similaires et les nommer. multiplyBy5multiplyBy10, et multiplyBy20, cela pourrait être traité beaucoup mieux en utilisant la fonction currying.

Ajoutez l'extrait de code suivant à votre terrain de jeu:

func multiplyBy (a: Int) -> IntFunction func nestedMultiply (b: Int) -> Int return a * b return nestedMultiply multiplyBy (10) (20) let multiplyBy5 = multiplyBy (5) multiplyBy5 (4)

Nous définissons le multiplier par(_:) fonction qui accepte un Int comme seul paramètre et retourne une fonction de type IntFunction, le type de données que nous avons défini précédemment dans ce tutoriel. Dans cette fonction, nous définissons une autre fonction, nestedMultiply (_ :). Nous imbriquons cette fonction dans la première afin qu’elle ne puisse pas être exécutée en dehors du multiplier par(_:) fonction et a accès au une paramètre d'entrée.

Les trois lignes sous la définition de fonction sont des exemples simples de la façon dont vous pouvez curryer les fonctions ensemble..

Bien que vous puissiez créer des fonctions de currying à l'aide de fonctions imbriquées, vous pouvez également les créer à l'aide de fermetures ou en définissant plusieurs jeux de paramètres. A titre d'exemple, ajoutez l'extrait de code suivant à votre terrain de jeu:

func add (a: Int) -> IntFunction return b dans a + b laisser add2 = add (2) add2 (4) func soustraire (a: Int) (b: Int) -> Int return b - a laisser soustraire5 = soustraire (5) soustraire5 (b: 8)

Comme vous pouvez le constater, ces deux nouvelles fonctions peuvent être combinées de la même manière que toutes les autres fonctions de ce didacticiel. La seule exception est qu'avec la fonction définie avec deux jeux de paramètres, vous devez nommer explicitement le second paramètre..

Il n'y a pas de limite au nombre de niveaux de fonction que vous pouvez implémenter dans votre code. Le code suivant montre un exemple de trois fonctions au curry et comment il diffère d'une fonction à trois paramètres.

func multiplier (a: Int, b: Int, c: Int) -> Int return a * b * c func multiplier (a: Int) -> (Int) -> IntFunction func nestedMultiply1 (b: Int) - > IntFunction func nestedMultiply2 (c: Int) -> Int return a * b * c return nestedMultiply2 return nestedMultiply1 multiplier (4, 5, 6) multiplier (4) (5) (6)

La principale différence entre ces deux fonctions de multiplication est que la version au curry peut effectivement être mise en pause et stockée dans une variable après le traitement du premier ou du second paramètre. Cela rend la fonction très facile à réutiliser et à passer comme objet.

Conclusion

Le curry fonctionnel dans Swift est un concept difficile à saisir, mais il repose essentiellement sur deux concepts clés:

  • créer des fonctions qui retournent d'autres fonctions
  • réduction des fonctions avec plusieurs arguments en une série de fonctions, chacune avec un argument

Il existe une variété de façons de curry fonctions ensemble et, alors que seul le Int type de données a été utilisé dans ce tutoriel, les mêmes processus peuvent être utilisés avec n’importe quel type de données dans vos projets Swift. Cela permet aux fonctions d'être stockées dans des variables et d'être utilisées plusieurs fois dans votre code..

Comme toujours, assurez-vous de laisser vos commentaires ci-dessous dans les commentaires..