Question

Ceci est un suivi de Pourquoi ai-je "modèles non-exhaustive en fonction ..." quand j'invoque ma fonction Haskell substring?

Je comprends que l'utilisation -Wall, GHC peut mettre en garde contre les modèles non-exhaustive. Je me demande quelle est la raison derrière ne pas en faire une erreur de compilation par défaut étant donné qu'il est toujours possible de définir explicitement une fonction partielle:

f :: [a] -> [b] -> Int
f [] _  = error "undefined for empty array"
f _ []  = error "undefined for empty array"
f (_:xs) (_:ys) = length xs + length ys

La question est GHC spécifique.

Est-ce parce que ...

  • personne ne voulait appliquer un compilateur Haskell pour effectuer ce genre d'analyse?
  • une recherche de motif non exhaustive peut trouver certains mais pas tous les cas?
  • fonctions partiellement définies sont considérées comme légitimes et utilisés assez souvent de ne pas imposer le genre de construction ci-dessus? Si tel est le cas, pouvez-vous me expliquer pourquoi les modèles non exhaustives sont utiles / légitimes?
Était-ce utile?

La solution

Il y a des cas où vous ne me dérange pas qu'un match de modèle est non-exhaustive. Par exemple, alors que cela pourrait ne pas être la mise en œuvre optimale, je ne pense pas que cela aiderait si elle ne compile pas:

fac 0 = 1
fac n | n > 0 = n * fac (n-1)

Que est non-exhaustive (les nombres négatifs ne correspondent à aucun cas) n'a pas vraiment pour l'utilisation typique de la fonction factoriel.

En outre, il pourrait ne pas être généralement possible de décider du compilateur si une correspondance est évidemment exhaustif:

mod2 :: Integer -> Integer
mod2 n | even n = 0
mod2 n | odd n  = 1

Ici tous les cas doivent être couverts, mais le compilateur ne peut probablement pas le détecter. Étant donné que les gardes le compilateur ne peut peut être arbitrairement complexe, toujours décider si les motifs sont exhaustifs. Bien sûr, cet exemple serait mieux écrit avec otherwise, mais je pense qu'il devrait aussi compiler sous sa forme actuelle.

Autres conseils

Vous pouvez utiliser -Werror pour transformer les avertissements en erreurs. Je ne sais pas si vous pouvez juste tourner les modèles non-exhaustive des avertissements en erreurs, désolé!

Quant à la troisième partie de votre question:

J'écris parfois un certain nombre de fonctions qui ont tendance à travailler en étroite collaboration et ont des propriétés que vous ne pouvez pas exprimer facilement dans Haskell. Au moins certaines de ces fonctions ont tendance à avoir des motifs non exhaustifs, généralement les « consommateurs ». Cela arrive, par exemple dans les fonctions qui sont « tri-de » inverses l'une de l'autre.

Un exemple de jouet:

duplicate :: [a] -> [a]
duplicate [] = []
duplicate (x:xs) = x : x : (duplicate xs)

removeDuplicates :: Eq a => [a] -> [a]
removeDuplicates [] = []
removeDuplicates (x:y:xs) | x == y = x : removeDuplicates xs

Maintenant, il est assez facile de voir que removeDuplicates (duplicate as) est égale à as (chaque fois que le type d'élément est en Eq), mais en général duplicate (removeDuplicates bs) plantera, car il y a un nombre impair d'éléments ou 2 éléments consécutifs diffèrent. Si elle ne tombe pas en panne, il est parce que bs a été produit par (ou aurait pu être produit par) duplicate en premier lieu !.

Nous avons donc les lois suivantes (non Haskell valide):

removeDuplicates . duplicate == id
duplicate . removeDuplicates == id (for values in the range of duplicate)

Maintenant, si vous voulez éviter les modèles non-exhaustive ici, vous pourriez faire removeDuplicates Maybe [a] de retour, ou ajouter des messages d'erreur pour les cas manquants. Vous pouvez même faire quelque chose le long des lignes de

newtype DuplicatedList a = DuplicatedList [a]

duplicate :: [a] -> DuplicatedList a
removeDuplicates :: Eq a => DuplicatedList a -> [a]
-- implementations omitted

Tout cela est nécessaire, parce que vous ne pouvez pas exprimer facilement « étant une liste de même longueur, avec des paires consécutives d'éléments étant égaux » dans le système de type Haskell (sauf si vous êtes Oleg:)

Mais si vous n'exporter removeDuplicates Je pense qu'il est parfaitement acceptable d'utiliser des modèles non-exhaustive ici. Dès que vous l'exporter, vous perdrez le contrôle des entrées et devra traiter les cas manquants!

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