153 votes

Qu'est-ce que le "lifting" en Haskell ?

Je ne comprends pas ce qu'est le "levage". Dois-je d'abord comprendre les monades avant de comprendre ce qu'est une "levée" ? (Je suis aussi complètement ignorant des monades :) Ou quelqu'un peut-il me l'expliquer avec des mots simples ?

10 votes

Peut-être utile, peut-être pas : haskell.org/haskellwiki/Lifting

199voto

Paul Johnson Points 8604

La levée est plus un modèle de conception qu'un concept mathématique (bien que je m'attende à ce que quelqu'un ici me réfute en montrant que les levées sont une catégorie ou autre).

Typiquement, vous avez un certain type de données avec un paramètre. Quelque chose comme

data Foo a = Foo { ...stuff here ...}

Supposons que vous trouvez que beaucoup d'utilisations de Foo prennent des types numériques ( Int , Double etc.) et vous devez sans cesse écrire du code qui déballe ces nombres, les ajoute ou les multiplie, puis les emballe à nouveau. Vous pouvez court-circuiter ce processus en n'écrivant qu'une seule fois le code de déballage et d'enroulement. Cette fonction est traditionnellement appelée "ascenseur" car elle ressemble à ceci :

liftFoo2 :: (a -> b -> c) -> Foo a -> Foo b -> Foo c

En d'autres termes, vous avez une fonction qui prend une fonction à deux arguments (comme la fonction (+) ) et le transforme en fonction équivalente pour Foos.

Donc maintenant vous pouvez écrire

addFoo = liftFoo2 (+)

Edit : plus d'informations

Vous pouvez bien sûr avoir liftFoo3 , liftFoo4 et ainsi de suite. Cependant, cela n'est souvent pas nécessaire.

Commencez par l'observation

liftFoo1 :: (a -> b) -> Foo a -> Foo b

Mais c'est exactement la même chose que fmap . Ainsi, plutôt que de liftFoo1 vous écrivez

instance Functor Foo where
   fmap f foo = ...

Si vous voulez vraiment une régularité totale, vous pouvez alors dire

liftFoo1 = fmap

Si vous pouvez faire Foo en un foncteur, peut-être pouvez-vous en faire un foncteur applicatif. En fait, si vous pouvez écrire liftFoo2 alors l'instance applicative ressemble à ceci :

import Control.Applicative

instance Applicative Foo where
   pure x = Foo $ ...   -- Wrap 'x' inside a Foo.
   (<*>) = liftFoo2 ($)

El (<*>) L'opérateur pour Foo a le type

(<*>) :: Foo (a -> b) -> Foo a -> Foo b

Il applique la fonction enveloppée à la valeur enveloppée. Donc, si vous pouvez implémenter liftFoo2 alors vous pouvez écrire ceci en fonction de cela. Ou bien vous pouvez l'implémenter directement et ne pas vous embarrasser de liftFoo2 parce que le Control.Applicative Le module comprend

liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c

et de même, il y a liftA y liftA3 . Mais vous ne les utilisez pas très souvent car il existe un autre opérateur.

(<$>) = fmap

Cela vous permet d'écrire :

result = myFunction <$> arg1 <*> arg2 <*> arg3 <*> arg4

Le terme myFunction <$> arg1 renvoie une nouvelle fonction enveloppée dans Foo :

ghci> :type myFunction
a -> b -> c -> d

ghci> :type myFunction <$> Foo 3
Foo (b -> c -> d)

Ceci peut à son tour être appliqué à l'argument suivant en utilisant (<*>) et ainsi de suite. Donc maintenant, au lieu d'avoir une fonction de levée pour chaque arité, vous avez juste une chaîne d'applicatifs, comme ceci :

ghci> :type myFunction <$> Foo 3 <*> Foo 4
Foo (c -> d)

ghci: :type myFunction <$> Foo 3 <*> Foo 4 <*> Foo 5
Foo d

28 votes

Il est probablement utile de rappeler que les ascenseurs doivent respecter les lois standards lift id == id y lift (f . g) == (lift f) . (lift g) .

15 votes

Les ascenseurs sont en effet "une catégorie ou quelque chose". Carlos vient d'énumérer les lois sur les foncteurs, où id y . sont la flèche d'identité et la composition de flèches d'une certaine catégorie, respectivement. Habituellement, lorsqu'on parle de Haskell, la catégorie en question est "Hask", dont les flèches sont des fonctions Haskell (en d'autres termes, id y . font référence aux fonctions Haskell que vous connaissez et aimez).

0 votes

J'aime la façon dont vous commencez en mentionnant un type avec un paramètre. C'est l'idée la plus importante de Monad. Je n'arrive toujours pas à croire que dans le livre Real World Haskell, l'auteur n'a pas expliqué que le monade est simplement une classe de type (consultez le chapitre sur les monades et la programmation par monade dans ce livre).

42voto

Martijn Points 3955

Celles de Paul et de Yairchu sont toutes deux de bonnes explications.

J'aimerais ajouter que la fonction levée peut avoir un nombre arbitraire d'arguments et qu'ils ne doivent pas nécessairement être du même type. Par exemple, vous pourriez aussi définir une fonction liftFoo1 :

liftFoo1 :: (a -> b) -> Foo a -> Foo b

En général, la levée des fonctions qui prennent 1 argument est capturée dans la classe de type Functor et l'opération de levage est appelée fmap :

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

Notez la similitude avec liftFoo1 Le type de l'entreprise. En fait, si vous avez liftFoo1 vous pouvez faire Foo une instance de Functor :

instance Functor Foo where
  fmap = liftFoo1

De plus, la généralisation de la levée à un nombre arbitraire d'arguments est appelée style applicatif . Ne vous y plongez pas avant d'avoir compris la levée des fonctions avec un nombre fixe d'arguments. Mais quand vous le ferez, Apprenez un Haskell contient un bon chapitre sur ce sujet. Le site Typeclassopedia est un autre bon document qui décrit Fecteur y Applicatif (ainsi que d'autres classes de type ; faites défiler la page jusqu'au chapitre de droite dans ce document).

J'espère que cela vous aidera !

26voto

yairchu Points 9694

Commençons par un exemple (des espaces blancs ont été ajoutés pour une présentation plus claire) :

> import Control.Applicative
> replicate 3 'a'
"aaa"
> :t replicate
replicate        ::         Int -> b -> [b]
> :t liftA2
liftA2 :: (Applicative f) => (a -> b -> c) -> (f a -> f b -> f c)
> :t liftA2 replicate
liftA2 replicate :: (Applicative f) =>       f Int -> f b -> f [b]
> (liftA2 replicate) [1,2,3] ['a','b','c']
["a","b","c","aa","bb","cc","aaa","bbb","ccc"]
> ['a','b','c']
"abc"

liftA2 transforme une fonction de types ordinaires en une fonction de les mêmes types enveloppés dans un Applicative comme des listes, IO etc.

Un autre ascenseur commun est lift de Control.Monad.Trans . Il transforme une action monadique d'une monade en une action d'une monade transformée.

En général, "ascenseur" ascenseurs une fonction/action dans un type "enveloppé" (de sorte que la fonction originale puisse fonctionner "sous l'enveloppe").

La meilleure façon de comprendre cela, ainsi que les monades, etc., et de comprendre pourquoi elles sont utiles, est probablement de coder et de les utiliser. Si vous avez codé quelque chose auparavant et que vous pensez que cela pourrait vous être utile (par exemple, cela rendra le code plus court, etc.), essayez-le et vous comprendrez facilement le concept.

16voto

Nasser Hadjloo Points 4781

Le lifting est un concept qui permet de transformer une fonction en une fonction correspondante dans un autre cadre (généralement plus général).

jeter un coup d'œil à http://haskell.org/haskellwiki/Lifting

42 votes

Oui, mais cette page commence par "We usually start with a (covariant) functor...". Pas vraiment convivial pour les débutants.

4 votes

Mais "functor" est lié, donc le débutant peut juste cliquer dessus pour voir ce qu'est un functor. Certes, la page liée n'est pas très bonne. Il faut que j'obtienne un compte et que je répare ça.

10 votes

C'est un problème que j'ai rencontré sur d'autres sites de programmation fonctionnelle : chaque concept est expliqué en termes d'autres concepts (non familiers) jusqu'à ce que le débutant fasse le tour complet (et le tour complet). Cela doit avoir un rapport avec le fait d'aimer la récursion.

0voto

Val Points 985

Selon ce tutoriel brillant un foncteur est un conteneur (comme Maybe<a> , List<a> o Tree<a> qui peut stocker des éléments d'un autre type, a ). J'ai utilisé la notation générique de Java, <a> pour le type d'élément a et pensez aux éléments comme à des baies sur l'arbre. Tree<a> . Il existe une fonction fmap qui prend une fonction de conversion d'éléments, a->b et conteneur functor<a> . Il s'applique a->b à chaque élément du conteneur, le convertissant effectivement en functor<b> . Lorsque seul le premier argument est fourni, a->b , fmap attend le functor<a> . C'est-à-dire qu'il faut fournir a->b seule transforme cette fonction de niveau élémentaire en la fonction functor<a> -> functor<b> qui fonctionne sur des conteneurs. Il s'agit de levage de la fonction. Comme le conteneur est également appelé un foncteur le recours aux foncteurs plutôt qu'aux monades est une condition préalable à la levée. Les monades sont en quelque sorte "parallèles" au lifting. Les deux reposent sur la notion de foncteur et font f<a> -> f<b> . La différence est que le levage utilise a->b pour la conversion, alors que Monad nécessite que l'utilisateur définisse a -> f<b> .

5 votes

Je t'ai donné une note inférieure, parce que "un foncteur est un conteneur" est un appât à flamme à saveur de troll. Exemple : les fonctions de certains r à un type (utilisons c pour la variété), sont des foncteurs. Ils ne "contiennent" pas de c 's. Dans ce cas, fmap est une composition de fonctions, prenant une fonction a -> b et une fonction r -> a un, pour vous en donner un nouveau, r -> b fonction. Toujours pas de conteneurs. Aussi, si je pouvais, je le noterais à nouveau pour la dernière phrase.

1 votes

Aussi, fmap est une fonction, et n'"attend" rien ; le "conteneur" étant un foncteur est le point essentiel de levage. De plus, les Monades sont, en quelque sorte, une idée double de la levée : une Monade vous permet d'utiliser quelque chose qui a été levée un nombre positif de fois, comme si elle n'avait été levée qu'une seule fois - ceci est mieux connu sous le nom de aplatissant .

2 votes

@BMeph To wait , to expect , to anticipate sont les synonymes. En disant "la fonction attend", je voulais dire "la fonction anticipe".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X