Quelles sont les utilisations de fonction id dans Haskell?
Il est utile comme argument pour fonctions d'ordre supérieur (fonctions qui prennent des fonctions comme arguments), où vous voulez qu'une valeur particulière reste inchangée.
Exemple 1 : Laissez une valeur seule si elle est dans un Just, sinon, retournez une valeur par défaut de 7.
Prelude Data.Maybe> :t maybe
maybe :: b -> (a -> b) -> Maybe a -> b
Prelude Data.Maybe> maybe 7 id (Just 2)
2
Exemple 2 : création d'une fonction via un pli:
Prelude Data.Maybe> :t foldr (.) id [(+2), (*7)]
:: (Num a) => a -> a
Prelude Data.Maybe> let f = foldr (.) id [(+2), (*7)]
Prelude Data.Maybe> f 7
51
Nous avons construit une nouvelle fonction f
en repliant une liste de fonctions avec (.)
, en utilisant id
comme cas de base.
Exemple 3 : le cas de base pour les fonctions de monoides (simplifié).
instance Monoid (a -> a) where
mempty = id
f `mappend` g = (f . g)
Semblable à notre exemple avec fold, les fonctions peuvent être traitées comme des valeurs concaténables, avec id
servant pour le cas vide et (.)
en annexe.
Exemple 4 : une fonction de hachage triviale.
Data.HashTable> h <- new (==) id :: IO (HashTable Data.Int.Int32 Int)
Data.HashTable> insert h 7 2
Data.HashTable> Data.HashTable.lookup h 7
Just 2
Les tables de hachage nécessitent une fonction de hachage. Mais que se passe-t-il si votre clé est déjà hachée? Passez ensuite la fonction id, à remplir comme méthode de hachage, avec une surcharge de performances nulle.
Si vous manipulez des nombres, en particulier avec l'addition et la multiplication, vous aurez remarqué l'utilité de 0 et 1. De même, si vous manipulez des listes, la liste vide s'avère assez pratique. De même, si vous manipulez des fonctions (très courantes en programmation fonctionnelle), vous remarquerez le même type d'utilité que id
.
Dans les langages fonctionnels, les fonctions sont des valeurs de première classe que vous pouvez transmettre en tant que paramètre. Ainsi, l'une des utilisations les plus courantes de id
apparaît lorsque vous passez une fonction en tant que paramètre à une autre fonction pour lui dire quoi faire. L'un des choix de ce qu'il faut faire est probablement "laissez-le tranquille" - dans ce cas, vous passez id
comme paramètre.
Supposons que vous cherchiez une sorte de solution à un casse-tête où vous faites un pas à chaque tour. Vous commencez avec un poste candidat pos
. À chaque étape, il y a une liste de transformations possibles que vous pourriez apporter à pos
(par exemple, glisser une pièce dans le puzzle). Dans un langage fonctionnel, il est naturel de représenter les transformations en tant que fonctions, vous pouvez donc maintenant faire une liste de mouvements à l'aide d'une liste de fonctions. Si "ne rien faire" est une décision légale dans ce casse-tête, alors vous représenteriez cela avec id
. Si vous ne l'avez pas fait, vous devrez gérer "ne rien faire" comme un cas spécial qui fonctionne différemment de "faire quelque chose". En utilisant id
, vous pouvez gérer tous les cas de manière uniforme dans une seule liste.
C'est probablement la raison pour laquelle presque toutes les utilisations de id
existent. Pour gérer "ne rien faire" uniformément avec "faire quelque chose".
Puisque nous trouvons de belles applications de id
. Ici, ayez un palindrome :)
import Control.Applicative
pal :: [a] -> [a]
pal = (++) <$> id <*> reverse
Je peux également vous aider à améliorer votre score de golf. À la place d'utiliser
($)
vous pouvez enregistrer un seul caractère en utilisant id.
par exemple.
zipWith id [(+1), succ] [2,3,4]
Un résultat intéressant, plus qu'utile.
Pour une réponse différente:
Je le fais souvent lors du chaînage de plusieurs fonctions via la composition:
foo = id
. bar
. baz
. etc
plus de
foo = bar
. baz
. etc
Il permet de modifier les choses plus facilement. On peut faire des choses similaires avec d'autres éléments "zéro", comme
foo = return
>>= bar
>>= baz
foos = []
++ bars
++ bazs
Imaginez que vous êtes un ordinateur, c'est-à-dire que vous pouvez exécuter une séquence d'étapes. Ensuite, si je veux que vous restiez dans votre état actuel, mais je dois toujours vous donner une instruction (je ne peux pas simplement couper le son et laisser le temps passer), quelle instruction dois-je vous donner? Id est la fonction créée pour cela, pour retourner l'argument inchangé (dans le cas de l'ordinateur précédent, l'argument serait son état) et pour avoir un nom pour lui. Cette nécessité n'apparaît que lorsque vous avez des fonctions d'ordre élevé, lorsque vous travaillez avec des fonctions sans tenir compte de leur contenu, ce qui vous oblige à représenter symboliquement même l'implémentation "ne rien faire". Analogiquement, 0 vu comme une quantité de quelque chose, est un symbole de l'absence de quantité. En fait, en algèbre, 0 et id sont considérés respectivement comme les éléments neutres des opérations + et ∘ (composition de la fonction), ou plus formellement:
pour tous les x du numéro de type:
pour toutes les fonctions de type f:
Chaque fois que vous avez besoin d'avoir une fonction quelque part, mais que vous voulez faire plus que simplement tenir sa place (avec 'undefined' comme exemple).
Il est également utile, comme (bientôt) le Dr Stewart l'a mentionné ci-dessus, lorsque vous devez passer une fonction comme argument à une autre fonction:
join = (>>= id)
ou comme résultat d'une fonction:
let f = id in f 10
(probablement, vous éditerez la fonction ci-dessus plus tard pour faire quelque chose de plus "intéressant" ...;)
Comme d'autres l'ont mentionné, id
est un merveilleux espace réservé lorsque vous avez besoin d'une fonction quelque part.