Question

Je me demande pourquoi ce morceau de code ne tapez vérification pas:

{-# LANGUAGE ScopedTypeVariables, Rank2Types, RankNTypes #-}
{-# OPTIONS -fglasgow-exts #-}

module Main where

foo :: [forall a. a]
foo = [1]

GHC se plaint:

Could not deduce (Num a) from the context ()
  arising from the literal `1' at exist5.hs:7:7

Étant donné que:

Prelude> :t 1
1 :: (Num t) => t
Prelude> 

il semble que le contexte (Num t) ne peut pas correspondre au contexte () de arg. Le point que je ne comprends pas est que, depuis () est plus générale que (Num t), celui-ci devrait inclure et de l'ancien. A ce rien à voir avec le manque de soutien pour Haskell sous-typage?

Merci pour tout commentaire à ce sujet.

Était-ce utile?

La solution

Vous n'êtes pas en utilisant la quantification existentielle ici. Vous utilisez les types de N rang.

Voici des moyens [forall a. a] que chaque élément doit avoir tous les types possibles (pas, tous). Donc [undefined, undefined] serait une liste valide de ce type et qui est essentiellement cela.

Pour en dire un peu: si une liste est de type [forall a. a] qui signifie que tous les éléments sont de type forall a. a. Cela signifie que toute fonction qui prend toute sorte d'argument, peut prendre un élément de cette liste comme argument. Ce n'est plus vrai si vous mettez dans un élément qui a un type plus spécifique que forall a. a, de sorte que vous ne pouvez pas.

Pour obtenir une liste qui peut contenir tout type, vous devez définir votre propre type de liste avec la quantification existentielle. Comme ceci:

data MyList = Nil | forall a. Cons a MyList
foo :: MyList
foo = Cons 1 Nil

Bien sûr, à moins que vous retenez les types d'éléments à au moins instancier Show, vous ne pouvez rien faire avec une liste de ce type.

Autres conseils

D'abord, votre exemple ne même pas obtenir loin avec moi pour le GHC actuel, parce que vous devez activer ImpredecativeTypes ainsi. Cela se traduit par un avertissement ImpredicativeTypes seront simplifiées ou supprimées dans la prochaine GHC. Donc, nous ne sommes pas en bon territoire ici. Néanmoins, en ajoutant la contrainte appropriée Num (de foo :: [forall a. Num a => a]) ne permet de compiler votre exemple.

Le congé de Let côté types imprédicatives et regarder un exemple plus simple:

data Foo = Foo (forall a. a)
foo = Foo 1

Cela ne compile pas aussi avec le Could not deduce (Num a) from the context () d'erreur.

Pourquoi? Eh bien, le type de promesses que vous allez donner quelque chose constructeur Foo avec la qualité que pour tout type a, elle produit un a. La seule chose qui satisfait c'est en bas. Un littéral entier, d'autre part, des promesses que pour tout type a qui est de la classe Num il produit une a. Ainsi, les types sont clairement incompatibles. On peut cependant tirer le forall un peu plus loin, pour obtenir ce que vous voulez sans doute:

data Foo = forall a. Foo a
foo = Foo 1

Alors que compiles. Mais que pouvons-nous faire? Eh bien, nous allons essayer de définir une fonction d'extraction:

unFoo (Foo x) = x

Oops! Quantified type variable 'a' escapes. Ainsi, nous pouvons définir, mais nous ne pouvons pas faire grand-chose intéressante avec elle. Si nous avons donné un contexte de classe, nous pourrions au moins utiliser certaines des fonctions de classe sur elle.

Il y a un temps et un lieu pour les existentiels, y compris ceux sans contexte de classe, mais son assez rare, surtout quand vous débutez. Lorsque vous finissez de les utiliser, il sera souvent dans le contexte de GADTs, qui sont un des types existentiels surensemble, mais où la façon dont existentiaux surgir sent tout à fait naturel.

Parce que la déclaration [forall a. a] est (en un sens) l'équivalent de dire: «J'ai une liste, et si vous (par exemple l'ordinateur) choisir un type, I garantie que les éléments de ladite liste sera ce type. "

Le compilateur « appelle votre bluff », pour ainsi parler, en se plaignant, « Je sais» que si vous me donnez un 1, que son type est dans la classe Num, mais vous avez dit que je pouvais choisir tout ce que je voulais taper à pour cette liste. "

En gros, vous essayez d'utiliser la valeur d'un type universel comme si elle était le type d'une valeur universelle. Ce ne sont pas la même chose, cependant.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top