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..
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 à voiture1
de 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 voiture1
la 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.
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. multiplyBy5
, multiplyBy10
, 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.
Le curry fonctionnel dans Swift est un concept difficile à saisir, mais il repose essentiellement sur deux concepts clés:
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..