2017-06-10 4 views
4

Je suis un newbie Haskell et je me demande pourquoi il n'y a pas d'exemple alternative pour Either mais un demi-groupe, qui se comporte comme j'attendre de solution de rechange:Pourquoi n'existe-t-il pas d'instance alternative pour Either mais un semigroupe qui se comporte similairement à l'alternative?

instance Semigroup (Either a b) where 
Left _ <> b = b 
a  <> _ = a 

Cette instance rejets ou corrige des « erreurs » et lorsque les deux les opérandes sont marqués avec Right, il prend le premier. N'est-ce pas exactement le «choix» que cette alternative offre?

je me attends à l'instance semigroupe à regarder à peu près comme:

instance (Semigroup b) => Semigroup (Either a b) where 
Left e <> _  = Left e 
_  <> Left e = Left e 
Right x <> Right y = Right (x <> y) 

Cela signifie qu'il se propage des erreurs et des résultats réguliers ajoute.

Je suppose que j'ai une mauvaise notion de Either ou des classes de types concernées.

+0

Cela semble lié: https://ghc.haskell.org/trac/ghc/ticket/9588 –

Répondre

4

Qu'attendriez-vous d'une instance Alternative pour vous donner. Je pense qu'une bonne façon pour vous d'avoir une idée de la façon dont Alternative et Semigroup diffèrent est de regarder un autre type qui a des cas pour les deux: par exemple Maybe String:

λ > Just "a" <> Just "b" 
Just "ab" 
λ > Just "a" <> Nothing 
Just "a" 
λ > Nothing <> Just "b" 
Just "b" 
λ > Nothing <> Nothing 
Nothing 


λ > Just "a" <|> Just "b" 
Just "a" 
λ > Just "a" <|> Nothing 
Just "a" 
λ > Nothing <|> Just "b" 
Just "b" 
λ > Nothing <|> Nothing 
Nothing 

Bon, la principale différence semble être pour Just "a" et Just "b". Cela est logique puisque vous les combinez dans le cas du Semigroup plutôt que de prendre l'option biaisée de gauche dans le cas de Alternative. Maintenant, pourquoi ne pas avoir une instance Alternative pour Either. Si vous regardez les fonctions qui font partie de la classe de type Alternative:

λ > :i Alternative 
class Applicative f => Alternative (f :: * -> *) where 
    empty :: f a 
    (<|>) :: f a -> f a -> f a 
    some :: f a -> f [a] 
    many :: f a -> f [a] 
    {-# MINIMAL empty, (<|>) #-} 

On dirait qu'il définit une notion de empty; c'est l'identité de l'opérateur (<|>). L'identité dans le cas signifie que l'alternative entre l'identité et quelque chose d'autre est toujours quelque chose d'autre.

Maintenant, comment construiriez-vous une identité pour Either e a? Si vous observez la contrainte sur l'instance Alternative, vous pouvez voir qu'il nécessite f pour avoir une instance Applicative. C'est bien, Either a une instance Applicative déclarée pour Either e. Comme vous pouvez le voir le Either est seulement un foncteur applicatif sur la deuxième variable de type (a dans le cas de Either e a). Donc, une identité pour Either e aurait besoin de e pour avoir aussi une identité. Bien qu'il soit possible de construire un type où e a une instance de Alternative vous ne pouvez pas créer une instance pour Alternative pour Either avec cette e car aucune contrainte de ce type n'existe dans la définition de classe de type (quelque chose comme: (Alternative e, Applicative (f e)) => Alternative (f e)).

TL; DR: Je suis désolé si je vous ai perdu avec mes divagations, court c'est que f dans le cas de Either est du mauvais genre, Alternative nécessite f :: * -> * tout Either est de genreEither :: * -> * -> *

Ainsi Maybe peut avoir une instance de Alternative parce qu'il a typeMaybe : * -> * et a une notion d'identité (Nothing) qui est requis par empty. Jetez un oeil à toutes les instances de Alternative et faites attention au type de chaque type de données d'instance.

Vous pouvez trouver le type d'un type de données dans ghci avec :k:

λ > :k Maybe 
Maybe :: * -> * 
λ > :k Either 
Either :: * -> * -> * 
+0

Ceci est une excellente réponse. Merci de prendre le temps! – ftor

+0

Désolé, un problème persiste: 'Just" a "<> Just" b "== Juste" ab "' comme prévu, mais 'Right" a "<> Right" b "== Droit" a "'. Pourquoi cette différence? – ftor

+0

À droite, l'instance de 'Semigroup' de' Soit a b' n'est en fait pas définie comme vous l'avez écrite. Il est totalement indépendant de si 'b' a une instance de' Semigroup' ou non. Il rejette simplement une valeur 'Left' quand c'est le terme gauche de' (<>) 'et retourne sinon le terme gauche. Checkout le code source réel [ici] (https://hackage.haskell.org/package/base-4.9.1.0/docs/src/Data.Semigroup.html#line-173) :-) Je ne suis pas sûr de ce que le La raison derrière cette définition est mais cela fonctionne plutôt bien pour vous puisque vous sembliez vouloir une instance 'Alternative'. –

2

par le ticket Dietrich Epp affiché ci-dessus, le problème avec Alternative est empty. Si vous avez:

instance Alternative (Either a) where ... 

Vous auriez besoin d'être en mesure de tirer une valeur Either a b « hors de l'air » qui était votre objet d'identité. Un exemple pourrait être possible:

instance (Monoid a)=> Alternative (Either a) where 
    empty = Left mempty 
    ... 

Vous demandez aussi pourquoi l'instance Semigroup est définie comme il est, et franchement je ne comprends pas non plus. Il semblerait que l'instance que vous proposez permettrait également une instance (compatible/légal) Monoid ainsi:

instance Monoid b=> Monoid (Either a b) where 
    mempty = Right mempty 

Et cela serait compatible avec l'instance Maybe (la relation algébrique entre Peut-être et soit être évident).

Donc la situation n'est pas bonne. Une partie du problème est Alternative est une sorte de classe de seconde classe si vous voulez; c'est un truc monoidal de type supérieur, mais sa relation avec Monoid et Semigroup, qui forment clairement et explicitement (dans les docs) une hiérarchie, n'est pas définie. Je suis sûr qu'il y a eu une grande quantité de discussion sur la liste de diffusion des bibliothèques, et s'il y a des solutions "correctes" évidentes, il est probable que leur déplacement pourrait causer (dans le pire des cas) une casse.

+0

La classe de type alternative semble provoquer fréquemment [des problèmes] (https://stackoverflow.com/questions/28681260/why-is-there-not-alternative-instance-for-control-applicative-const), également en raison de la lois sous-jacentes. Merci! – ftor