55 votes

Aide à comprendre les flèches dans Haskell

J'ai essayé d'obtenir une poignée sur les flèches, car ils sont la base de la plupart des PRF implémentations. Je crois que je comprends l'idée de base - qu'elles sont liées à des monades, mais stockent des informations statiques à lier chaque opérateur de sorte que vous pouvez marcher à travers une chaîne de flèches et de regarder les informations statiques sans avoir à évaluer l'ensemble de la flèche.

Mais je me suis perdu au moment où on commence à discuter de premier, deuxième, et le swap. Que dois-2-tuples ont à faire avec des flèches? Tutoriels présents le n-uplet des trucs comme si c'était une étape logique suivante, mais je ne suis pas vraiment voir la connexion. Pour cette question, quelle est la flèche de la syntaxe signifie intuitivement?

Merci.

48voto

KennyTM Points 232647

Veuillez prendre un coup d'oeil dans http://www.haskell.org/yampa/AFPLectureNotes.pdfqui explique comment les Flèches de travail en PRF.

2-tuples sont utilisés dans la définition de Flèches, parce que c'est nécessaire pour représenter un arrowized fonction prenant 2 arguments.

En fibre de verre, les constantes et les variables sont souvent représentés comme des flèches qui ignore son "entrée", par exemple

twelve, eleven :: Arrow f => f p Int
twelve = arr (const 12)
eleven = arr (const 11)

Fonction des applications sont alors transformées en des compositions (>>>):

# (6-) 12

arr (6-) <<< twelve

Maintenant, comment faire tourner un 2-fonction d'argument en flèche? Par exemple

(+) :: Num a => a -> a -> a

en raison de nourrissage que l'on peut traiter cela comme une fonction retournant une fonction. Donc

arr (+) :: (Arrow f, Num a) => f a (a -> a)

maintenant, nous allons l'appliquer à une constante

arr (+)             -- # f     a (a -> a)
  <<< twelve        -- # f b Int
                      :: f b     (Int -> Int)

+----------+      +-----+      +--------------+
| const 12 |----> | (+) |  ==  | const (+ 12) |
+----------+      +-----+      +--------------+

hé, attendez, ça ne fonctionne pas. Le résultat est toujours une flèche qui retourne une fonction, mais nous nous attendons à quelque chose qui s'apparente à l' f Int Int. Nous remarquons que nourrissage échoue en Flèche parce que seule la composition est autorisé. Par conséquent, nous devons uncurry la fonction première

uncurry :: (a -> b -> c) -> ((a, b) -> c)

uncurry (+) :: Num a => (a, a) -> a

Ensuite, nous avons la flèche

(arr.uncurry) (+) :: (Num a, Arrow f) => f (a, a) a

Le 2-n-uplet se pose à cause de cela. Puis le tas de fonctions comme &&& sont nécessaires pour faire face à ces 2-tuples.

(&&&) :: f a b -> f a d -> f a (b, d)

ensuite, l'ajout peut être correctement effectuée.

(arr.uncurry) (+)        -- # f   (a,    a) a
  <<<     twelve         -- # f b  Int
      &&& eleven         -- # f b      Int
                           :: f b           a

+--------+
|const 12|-----.
+--------+     |       +-----+      +----------+
              &&&====> | (+) |  ==  | const 23 |
+--------+     |       +-----+      +----------+
|const 11|-----'
+--------+

(Maintenant, pourquoi n'avons-nous pas besoin des choses comme &&&& , pour les 3-n-uplets pour les fonctions ayant 3 arguments? Parce qu'un ((a,b),c) peut être utilisé à la place.)


Edit: a Partir de John Hughes, le papier original de Généraliser les Monades de Flèches, il indique la raison que

4.1 les Flèches et les Paires

Cependant, même si dans le cas de monades les opérateurs return et >>= sont tout ce que nous devons commencer à écrire du code utile, pour les flèches analogues des opérateurs arr et >>> ne sont pas suffisantes. Même le simple monadique fonction d'addition que nous avons vu plus tôt

   add :: Monad m => m Int -> m Int -> m Int
   add x y = x >>= \u -> (y >>= \v -> return (u + v))

ne peut pas encore être exprimé dans une forme de flèche. Prise de dépendance sur une entrée explicite, on voit qu'une définition analogue devrait prendre la forme

   add :: Arrow a => a b Int -> a b Int -> a b Int
   add f g = ...

où nous devons combiner f et g dans la séquence. La seule séquençage de l'opérateur est disponible >>>, mais f et g n'ont pas le droit de types composés. En effet, l' add fonction des besoins pour enregistrer l'entrée de type b à travers le calcul de l' f, de manière à être en mesure de fournir la même entrée d' g. De même, le résultat d' f doivent être enregistrées à travers le calcul de l' g, de sorte que les deux résultats peuvent éventuellement être ajoutés et retourné. La flèche combinators jusqu'à présent introduit de nous donner aucun moyen d'enregistrer une valeur dans un autre calcul, et donc nous n'avons pas d'autre alternative que d'introduire un autre combinator.

-11voto

user268396 Points 4624

Quelles flèches? Vous voulez dire des flèches en (\x -> func x) , ou en [ x*x | x <- [1..10]] ?

La première est l'application lamba: le point qui suit une déclaration de symbole dans une instruction lambda; et si vous décompressez la sémantique, elle convertira fondamentalement let x = some_value in func x en une fonction qui lui est propre: définissez une fonction qui appelle func sur son opérande. La seconde est analogue à la théorie des ensembles: prenons x dans l’ensemble des nombres naturels compris entre 1 et 10 (inclus).

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