Je ne comprends pas ce qu'est «soulever». Dois-je d'abord comprendre les monades avant de comprendre ce qu'est un «ascenseur»? (Moi aussi, j'ignore complètement les monades :) Ou quelqu'un peut-il me l'expliquer avec des mots simples?
138
Réponses:
Le levage est plus un modèle de conception qu'un concept mathématique (même si je m'attends à ce que quelqu'un ici me réfute maintenant en montrant en quoi les ascenseurs sont une catégorie ou quelque chose).
En règle générale, vous avez un type de données avec un paramètre. Quelque chose comme
Supposons que vous trouviez que de nombreuses utilisations de
Foo
types numériques prennent (Int
,Double
etc.) et que vous continuiez à écrire du code qui déballe ces nombres, les ajoute ou les multiplie, puis les rembobine. Vous pouvez court-circuiter cela en écrivant une fois le code de déroulement et d'enroulement. Cette fonction est traditionnellement appelée «ascenseur» car elle ressemble à ceci:En d'autres termes, vous avez une fonction qui prend une fonction à deux arguments (comme l'
(+)
opérateur) et la transforme en fonction équivalente pour Foos.Alors maintenant tu peux écrire
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
Mais c'est exactement la même chose que
fmap
. Alors plutôt queliftFoo1
tu écriraisSi vous voulez vraiment une régularité complète, vous pouvez alors dire
Si vous pouvez en faire
Foo
un foncteur, vous pouvez peut-être en faire un foncteur applicatif. En fait, si vous pouvez écrire,liftFoo2
l'instance applicative ressemble à ceci:L'
(<*>)
opérateur de Foo a le typeIl applique la fonction encapsulée à la valeur encapsulée. Donc, si vous pouvez mettre en œuvre,
liftFoo2
vous pouvez l'écrire en termes de cela. Ou vous pouvez l'implémenter directement et ne pas vous embêterliftFoo2
, car leControl.Applicative
module comprendet de même il y a
liftA
etliftA3
. Mais vous ne les utilisez pas très souvent car il y a un autre opérateurCela vous permet d'écrire:
Le terme
myFunction <$> arg1
renvoie une nouvelle fonction encapsulée dans Foo. Cela peut à son tour être appliqué à l'argument suivant en utilisant(<*>)
, et ainsi de suite. Alors maintenant, au lieu d'avoir une fonction d'ascenseur pour chaque arité, vous avez juste une guirlande d'applicatifs.la source
lift id == id
etlift (f . g) == (lift f) . (lift g)
.id
et.
sont respectivement la flèche d'identité et la composition de flèches d'une certaine catégorie. Habituellement, quand on parle de Haskell, la catégorie en question est "Hask", dont les flèches sont des fonctions Haskell (en d'autres termes,id
et.
font référence aux fonctions Haskell que vous connaissez et aimez).instance Functor Foo
, noninstance Foo Functor
, non? Je modifierais moi-même mais je ne suis pas sûr à 100%.Paul et yairchu sont tous deux de bonnes explications.
Je voudrais 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 pouvez également définir un liftFoo1:
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éefmap
:Notez la similitude avec
liftFoo1
le type de. En fait, si c'est le casliftFoo1
, vous pouvez créerFoo
une instance deFunctor
:De plus, la généralisation du levage à un nombre arbitraire d'arguments est appelée style applicatif . Ne vous donnez pas la peine de plonger dans cela jusqu'à ce que vous ayez saisi la levée des fonctions avec un nombre fixe d'arguments. Mais quand vous le faites, Learn you a Haskell a un bon chapitre à ce sujet. Le Typeclassopedia est un autre bon document qui décrit Functor et Applicative (ainsi que d'autres classes de types; faites défiler jusqu'au chapitre droit de ce document).
J'espère que cela t'aides!
la source
Commençons par un exemple (un espace blanc est ajouté pour une présentation plus claire):
liftA2
transforme une fonction de types simples en une fonction des mêmes types enveloppée dans unApplicative
, comme des listesIO
, etc.Un autre ascenseur commun est
lift
deControl.Monad.Trans
. Il transforme une action monadique d'une monade en une action d'une monade transformée.En général, "lever" lève une fonction / action dans un type "enveloppé" (de sorte que la fonction d'origine se met au travail "sous les enveloppes").
La meilleure façon de comprendre cela, et les monades etc., et de comprendre pourquoi elles sont utiles, est probablement de les coder et de les utiliser. S'il y a quelque chose que vous avez précédemment codé et que vous soupçonnez de pouvoir en bénéficier (c'est-à-dire que cela raccourcira le code, etc.), essayez-le et vous comprendrez facilement le concept.
la source
Le levage est un concept qui vous permet de transformer une fonction en une fonction correspondante dans un autre paramètre (généralement plus général)
jetez un œil à http://haskell.org/haskellwiki/Lifting
la source
Selon ce tutoriel brillant , un foncteur est un conteneur (comme
Maybe<a>
,List<a>
ouTree<a>
qui peut stocker des éléments d'un autre type,a
). J'ai utilisé la notation générique Java,,<a>
pour le type d'élémenta
et je considère les éléments comme des baies sur l'arbreTree<a>
. Il existe une fonctionfmap
qui prend une fonction de conversion d'élémenta->b
et un conteneurfunctor<a>
. Il s'appliquea->b
à chaque élément du conteneur en le convertissant efficacement enfunctor<b>
. Lorsque seul le premier argument est fournia->b
,fmap
attend lefunctor<a>
. Autrement dit, la fourniturea->b
seule transforme cette fonction au niveau de l'élément en fonctionfunctor<a> -> functor<b>
qui opère sur les conteneurs. C'est ce qu'on appelle le levagede la fonction. Parce que le conteneur est également appelé un foncteur , les Functors plutôt que les Monades sont un prérequis pour le levage. Les monades sont en quelque sorte «parallèles» au levage. Les deux s'appuient sur la notion de Functor et fontf<a> -> f<b>
. La différence est que le levage utilisea->b
pour la conversion alors que Monad oblige l'utilisateur à définira -> f<b>
.la source
r
à un type (utilisonsc
pour la variété), sont des Functors. Ils ne «contiennent» aucunc
. Dans ce cas, fmap est une composition de fonction, prenant unea -> b
fonction et uner -> a
autre, pour vous donner une nouveller -> b
fonction. Toujours pas de conteneurs Et si je pouvais, je le marquerais à nouveau pour la dernière phrase.fmap
est une fonction, et n'attend rien; Le "container" étant un Functor, c'est tout l'intérêt du levage. En outre, les Monades sont, si quelque chose, une double idée de la levée: une Monade vous permet d'utiliser quelque chose qui a été soulevé un certain nombre de fois positif, comme s'il n'avait été soulevé qu'une seule fois - c'est mieux connu sous le nom d' aplatissement .To wait
,to expect
,to anticipate
sont les synonymes. En disant «fonction attend», je voulais dire «fonction anticipe».b = 5 : a
etf 0 = 55
f n = g n
, les deux impliquent une pseudo-mutation du "conteneur". Aussi le fait que les listes sont généralement stockées complètement en mémoire alors que les fonctions sont généralement stockées sous forme de calcul. Mais la mémorisation / les listes monorphes qui ne sont pas stockées entre les appels cassent la merde de cette idée.