En regardant à travers le Haskell Prelude, je vois une fonction const
:
const x _ = x
Je n'arrive pas à trouver quoi que ce soit de pertinent concernant cette fonction.
À quoi ça sert? Quelqu'un peut-il donner un exemple où cette fonction pourrait être utilisée?
backgroundColor :: Text -> Color
est pour moibackgroundColor = const White
Réponses:
C'est utile pour passer à des fonctions d'ordre supérieur lorsque vous n'avez pas besoin de toute leur flexibilité. Par exemple, l'opérateur de séquence monadique
>>
peut être défini en termes d'opérateur de liaison monadique commeC'est un peu plus soigné que d'utiliser un lambda
et vous pouvez même l'utiliser sans point
bien que je ne recommande pas particulièrement cela dans ce cas.
la source
map (const 42) [1..5]
résultats[42, 42, 42, 42, 42]
.const
est utile pour appliquer à un seul argument pour produire une fonction là où on en a besoin (comme passer àmap
).head = foldr const (error "Prelude.head: empty list")
Pour ajouter à l'excellente réponse directe de hammar: les fonctions humbles comme
const
etid
sont vraiment utiles en tant que fonction d'ordre supérieur pour la même raison qu'elles sont fondamentales dans le calcul combinateur SKI .Non pas que je pense que les fonctions préliminaires de haskell ont été modelées consciemment d'après ce système formel ou quoi que ce soit. C'est juste que créer de riches abstractions dans haskell est très facile, donc vous voyez souvent ces types de choses théoriques devenir pratiquement utiles.
Plug sans vergogne, mais j'ai blogué sur la façon dont l'instance Applicative pour
(->)
est en fait les combinateursS
et ici , si c'est le genre de chose que vous aimez.K
la source
((->) e)
est également la monade du lecteur - avecReader
et autres étant simplement desnewtype
wrappers - et laask
fonction est alorsid
, donc c'est aussi leI
combinateur. Si vous regardez plutôt originale base de BCKW de Haskell Curry,B
,K
etW
sontfmap
,return
etjoin
respectivement.Un exemple simple d'utilisation
const
estData.Functor.(<$)
. Avec cette fonction, vous pouvez dire: j'ai ici un foncteur avec quelque chose d'ennuyeux dedans, mais à la place je veux avoir cette autre chose intéressante dedans, sans changer la forme du foncteur. Par exempleLa définition est:
ou écrit pas aussi inutile:
Vous voyez comment
const
est utilisé ici pour "oublier" l'entrée.la source
La plupart des autres réponses traitent d'applications relativement ésotériques (du moins pour le nouveau venu) de
const
. En voici un simple: vous pouvez utiliserconst
pour vous débarrasser d'un lambda qui prend deux arguments, jette le premier mais fait quelque chose d'intéressant avec le second.Par exemple, la mise en œuvre suivante (inefficace mais instructive) de
length
,peut être réécrit comme
ce qui est peut-être plus élégant.
L'expression
const (1+)
est en effet sémantiquement équivalente à\_ acc -> 1 + acc
, car elle prend un argument, le jette et renvoie la section(1+)
.la source
Une autre utilisation consiste à implémenter des fonctions membres de classe qui ont un argument factice qui ne doit pas être évalué (utilisé pour résoudre les types ambigus). Exemple qui pourrait être dans Data.bits:
En utilisant const, nous disons explicitement que nous définissons des valeurs constantes.
Personnellement, je n'aime pas l'utilisation de paramètres factices, mais s'ils sont utilisés dans une classe, c'est une manière plutôt agréable d'écrire des instances.
la source
const
peut être simplement l'implémentation que vous recherchez en conjonction avec d'autres fonctions. Voici un exemple que j'ai découvert.Disons que nous voulons réécrire une structure de 2-tuples en une autre structure de 2-tuples. Je pourrais l'exprimer ainsi:
Je peux donner une définition simple avec la correspondance de motifs:
Et si je veux une solution inutile (tacite) pour ce genre de réécritures? Un peu de réflexion et de bidouillage plus tard, la réponse est que nous pouvons exprimer toutes les réécritures avec
(&&&), const, (.), fst, snd
. Notez que(&&&)
c'est deControl.Arrow
.La solution de l'exemple utilisant ces fonctions est:
Notez la similitude avec
(a,(c,(5,a)))
. Et si on remplace&&&
par,
? Ensuite, il lit:Remarquez comment
a
est le premier élément du premier élément, et c'est ce que lesfst.fst
projets. Remarquez commentc
est le premier élément du deuxième élément, et c'est ce que lesfst.snd
projets. Autrement dit, les variables deviennent le chemin vers leur source.const
nous permet d'introduire des constantes. Intéressant comment le nom s'aligne avec le sens!Je puis généralisé cette idée avec Applicative de sorte que vous pouvez écrire une fonction dans un style inutile (tant que vous avez une analyse de cas disponible en fonctions, telles que
maybe
,either
,bool
). Encore une fois,const
joue le rôle d'introduire des constantes. Vous pouvez voir ce travail dans le package Data.Function.Tacit .Lorsque vous commencez de manière abstraite, à l'objectif, puis que vous travaillez vers une implémentation, vous pouvez être surpris par les réponses. C'est-à-dire qu'une fonction peut être aussi mystérieuse que n'importe quel rouage d'une machine. Cependant, si vous reculez pour faire apparaître la machine entière, vous pouvez comprendre le contexte dans lequel ce rouage est nécessaire.
la source
Supposons que vous souhaitiez créer une liste
Nothings
égale à la longueur d'une chaîne. Asconst
renvoie son premier argument, quel que soit le second, vous pouvez faire:ou, plus explicitement:
la source
Supposons que vous souhaitiez faire pivoter une liste. C'est une façon idiomatique de le faire dans Haskell:
rotate :: Int -> [a] -> [a] rotate _ [] = [] rotate n xs = zipWith const (drop n (cycle xs)) xs
Cette fonction zippe deux tableaux avec la fonction
const
, le premier étant un tableau cyclique infini, le second étant le tableau avec lequel vous avez commencé.const
agit comme la vérification des limites et utilise le tableau d'origine pour terminer le tableau cyclique.Voir: Faire pivoter une liste dans Haskell
la source
Supposons que vous souhaitiez générer toutes les sous-séquences d'une liste donnée.
Pour chaque élément de la liste, à un moment donné, vous avez le choix entre True (l'inclure dans la sous-séquence courante) ou False (ne pas l'inclure). Cela peut être fait en utilisant la fonction filterM .
Comme ça:
Par exemple, nous voulons toutes les sous-séquences de
[1..4]
.la source