web-dev-qa-db-fra.com

Comment fonctionnent les fonctions à Haskell?

J'essaie d'apprendre Haskell et je suis à travers toutes les bases. Mais maintenant je suis coincé, essayant de me faire face aux foncteurs.

J'ai lu que "un foncteur transforme une catégorie dans une autre catégorie". Qu'est-ce que ça veut dire?

Je sais que c'est beaucoup à poser, mais quelqu'un pourrait-il me donner un anglais clair Explication des foncteurs ou peut-être un cas d'utilisation simple?

46
Matias Rasmussen

Une explication floue serait qu'un Functor est une sorte de conteneur et une fonction associée fmap qui vous permet de modifier tout ce qui est contenu, étant donné une fonction qui transforme le contenu.

Par exemple, les listes sont ce type de conteneur, de sorte que fmap (+1) [1,2,3,4] rendements [2,3,4,5].

Maybe peut également être effectué un cocceur, tel que fmap toUpper (Just 'a') rendement Just 'A'.

Le type général de fmap montre tout à fait ce qui se passe:

fmap :: Functor f => (a -> b) -> f a -> f b

Et les versions spécialisées peuvent rendre plus claire. Voici la version de la liste:

fmap :: (a -> b) -> [a] -> [b]

Et la version peut-être:

fmap :: (a -> b) -> Maybe a -> Maybe b

Vous pouvez obtenir des informations sur les instances standard Functor en interrogeant GHCI avec :i Functor Et de nombreux modules définissent plus d'instances de Functors (et d'autres classes de types.)

S'il vous plaît, ne prenez pas le mot "conteneur" trop au sérieux, cependant. Functors sont un concept bien défini, mais vous pouvez souvent en raisonner avec cette analogie floue.

Votre meilleur pari dans la compréhension de ce qui se passe est simplement de lire la définition de chacune des instances, ce qui devrait vous donner une intuition sur ce qui se passe. De là, ce n'est qu'une petite étape pour formaliser vraiment votre compréhension du concept. Ce qui doit être ajouté, c'est une clarification de ce que notre "conteneur" est vraiment et que chaque instance satisfait beaucoup à une paire de législations simples.

57
Sarah

Dans HASKELL, les foncteurs capturent la notion d'avoir des conteneurs de "substance", de sorte que vous puissiez manipuler cette "substance" sans changer la forme du conteneur.

Les foncteurs fournissent une seule fonction, fmap, qui vous permet de le faire, en prenant une fonction régulière et en "levage" à une fonction de conteneurs d'un type d'élément à un autre:

fmap :: Functor f => (a -> b) -> (f a -> f b) 

Par exemple, [], le constructeur de type de liste est un aménager:

> fmap show [1, 2, 3]
["1","2","3"]

de même, de nombreux autres constructeurs de type Haskell, comme Maybe et Map Integer1:

> fmap (+1) (Just 3)
Just 4
> fmap length (Data.Map.fromList [(1, "hi"), (2, "there")])
fromList [(1,2),(2,5)]

Notez que fmap n'est pas autorisé à modifier la "forme" du conteneur, donc si, par exemple, vous fmap une liste, le résultat comporte le même nombre d'éléments, et si vous fmap a Just Il ne peut pas devenir un Nothing. En termes formels, nous avons besoin que fmap id = id, c'est-à-dire si vous fmap la fonction d'identité, rien ne change.

Jusqu'ici, j'ai utilisé le terme "conteneur", mais c'est vraiment un peu plus général que cela. Par exemple, IO est également un foncteur et ce que nous entendons par "forme" dans ce cas est que fmap sur une action IO ne devrait pas changer le Effets secondaires. En fait, toute monade est un foncteur2.

Dans la théorie de la catégorie, les foncteurs vous permettent de convertir entre différentes catégories, mais à Haskell, nous n'avons vraiment qu'une catégorie, souvent appelée hask. Par conséquent, tous les foncteurs de Haskell se convertissent de HASK à HASK. Ils sont donc ce que nous appelons les endofuncteurs (foncteurs d'une catégorie à elle-même).

Dans leur forme la plus simple, les foncteurs sont un peu ennuyeux. Il n'y a que tant que vous pouvez faire avec une seule opération. Cependant, une fois que vous avez commencé à ajouter des opérations, vous pouvez passer de foncteurs réguliers à des foncteurs applicatifs vers les monades et les choses qui obtiennent rapidement beaucoup plus intéressante, mais cela dépasse la portée de cette réponse.

1 Mais Set n'est pas, car il ne peut stocker que les types Ord. Les foncteurs doivent pouvoir contenir n'importe quel type.
2 En raison des raisons historiques, Functor n'est pas une superclasse de Monad, bien que beaucoup de gens pensent que cela devrait être.

8
hammar